00001 #include "SimTracker/SiStripDigitizer/interface/SiLinearChargeDivider.h"
00002 #include "DataFormats/GeometryVector/interface/LocalPoint.h"
00003 #include "DataFormats/GeometryVector/interface/LocalVector.h"
00004 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00005 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00006
00007 SiLinearChargeDivider::SiLinearChargeDivider(const edm::ParameterSet& conf, CLHEP::HepRandomEngine& eng):
00008 conf_(conf),rndEngine(eng),theParticleDataTable(0){
00009
00010 peakMode=conf_.getParameter<bool>("APVpeakmode");
00011
00012
00013 timeResPeak=conf_.getParameter<double>("SigmaShapePeak");
00014 timeResDeco=conf_.getParameter<double>("SigmaShapeDeco");
00015
00016
00017 fluctuateCharge=conf_.getParameter<bool>("LandauFluctuations");
00018
00019
00020
00021 chargedivisionsPerStrip=conf_.getParameter<int>("chargeDivisionsPerStrip");
00022
00023
00024 deltaCut=conf_.getParameter<double>("DeltaProductionCut");
00025
00026
00027
00028
00029 cosmicShift=conf_.getUntrackedParameter<double>("CosmicDelayShift");
00030
00031 fluctuate = new SiG4UniversalFluctuation(rndEngine);
00032 }
00033
00034 SiLinearChargeDivider::~SiLinearChargeDivider(){
00035 delete fluctuate;
00036 }
00037
00038 SiChargeDivider::ionization_type
00039 SiLinearChargeDivider::divide(const PSimHit& hit, const LocalVector& driftdir, double moduleThickness, const StripGeomDetUnit& det) {
00040
00041 int NumberOfSegmentation =
00042 (int)(1+chargedivisionsPerStrip*fabs(driftXPos(hit.exitPoint(), driftdir, moduleThickness)-driftXPos(hit.entryPoint(), driftdir, moduleThickness))/(det.specificTopology()).localPitch(hit.localPosition()));
00043
00044 float eLoss = hit.energyLoss();
00045
00046 float decSignal = TimeResponse(hit, det);
00047
00048 ionization_type _ionization_points;
00049
00050 _ionization_points.resize(NumberOfSegmentation);
00051
00052 float energy;
00053
00054
00055
00056 LocalVector direction = hit.exitPoint() - hit.entryPoint();
00057
00058 float* eLossVector = new float[NumberOfSegmentation];
00059
00060 if( fluctuateCharge ) {
00061 int pid = hit.particleType();
00062 float momentum = hit.pabs();
00063 float length = direction.mag();
00064 fluctuateEloss(pid, momentum, eLoss, length, NumberOfSegmentation, eLossVector);
00065 }
00066
00067 for ( int i = 0; i != NumberOfSegmentation; i++) {
00068 if( fluctuateCharge ) {
00069 energy=eLossVector[i]*decSignal/eLoss;
00070 EnergyDepositUnit edu(energy,hit.entryPoint()+float((i+0.5)/NumberOfSegmentation)*direction);
00071 _ionization_points[i] = edu;
00072 }else{
00073 energy=decSignal/float(NumberOfSegmentation);
00074 EnergyDepositUnit edu(energy,hit.entryPoint()+float((i+0.5)/NumberOfSegmentation)*direction);
00075 _ionization_points[i] = edu;
00076 }
00077 }
00078
00079 delete[] eLossVector;
00080 return _ionization_points;
00081 }
00082
00083 void SiLinearChargeDivider::fluctuateEloss(int pid, float particleMomentum,
00084 float eloss, float length,
00085 int NumberOfSegs,float elossVector[]) {
00086
00087
00088 float dedx;
00089 if( length > 0.) dedx = eloss/length;
00090 else dedx = eloss;
00091
00092 assert(theParticleDataTable != 0);
00093 ParticleData const * particle = theParticleDataTable->particle( pid );
00094 double particleMass = 139.57;
00095 if(particle == 0)
00096 {
00097 LogDebug("SiLinearChargeDivider") << "Cannot find particle of type "<<pid
00098 << " in the PDT we assign to this particle the mass of the Pion";
00099 }
00100 else
00101 {
00102 particleMass = particle->mass()*1000;
00103 }
00104
00105
00106 if(fabs(particleMass)<1.e-6 || pid == 22)
00107 particleMass = 139.57;
00108
00109 float segmentLength = length/NumberOfSegs;
00110
00111
00112 float de=0.;
00113 float sum=0.;
00114 double segmentEloss = (1000.*eloss)/NumberOfSegs;
00115 for (int i=0;i<NumberOfSegs;i++) {
00116
00117
00118
00119
00120 double deltaCutoff = deltaCut;
00121 de = fluctuate->SampleFluctuations(double(particleMomentum*1000.),
00122 particleMass, deltaCutoff,
00123 double(segmentLength*10.),
00124 segmentEloss )/1000.;
00125 elossVector[i]=de;
00126 sum +=de;
00127 }
00128
00129 if(sum>0.) {
00130
00131 float ratio = eloss/sum;
00132 for (int ii=0;ii<NumberOfSegs;ii++) elossVector[ii]= ratio*elossVector[ii];
00133 } else {
00134 float averageEloss = eloss/NumberOfSegs;
00135 for (int ii=0;ii<NumberOfSegs;ii++) elossVector[ii]= averageEloss;
00136 }
00137 return;
00138 }
00139
00140 float SiLinearChargeDivider::TimeResponse( const PSimHit& hit, const StripGeomDetUnit& det ) {
00141 if (peakMode) {
00142 return this->PeakShape( hit, det );
00143 } else {
00144 return this->DeconvolutionShape( hit, det );
00145 }
00146 }
00147
00148 float SiLinearChargeDivider::PeakShape(const PSimHit& hit, const StripGeomDetUnit& det){
00149 float dist = det.surface().toGlobal(hit.localPosition()).mag();
00150 float t0 = dist/30.;
00151 float SigmaShape = timeResPeak;
00152 float tofNorm = (hit.tof() - cosmicShift - t0)/SigmaShape;
00153
00154 float readTimeNorm = -tofNorm;
00155
00156 if (1 + readTimeNorm > 0) {
00157 return hit.energyLoss()*(1 + readTimeNorm)*exp(-readTimeNorm);
00158 } else {
00159 return 0.;
00160 }
00161 }
00162
00163 float SiLinearChargeDivider::DeconvolutionShape(const PSimHit& hit, const StripGeomDetUnit& det){
00164 float dist = det.surface().toGlobal(hit.localPosition()).mag();
00165 float t0 = dist/30.;
00166 float SigmaShape = timeResDeco;
00167 float tofNorm = (hit.tof() - cosmicShift - t0)/SigmaShape;
00168
00169 float readTimeNorm = -tofNorm;
00170
00171 return hit.energyLoss()*exp(-0.5*readTimeNorm*readTimeNorm);
00172 }
00173
00174 void SiLinearChargeDivider::setParticleDataTable(const ParticleDataTable * pdt)
00175 {
00176 theParticleDataTable = pdt;
00177 }
00178
00179
00180 float SiLinearChargeDivider::driftXPos
00181 (const Local3DPoint& pos, const LocalVector& drift, double moduleThickness){
00182
00183 double tanLorentzAngleX = drift.x()/drift.z();
00184
00185 double segX = pos.x();
00186 double segZ = pos.z();
00187
00188 double thicknessFraction = (moduleThickness/2.-segZ)/moduleThickness ;
00189
00190 thicknessFraction = thicknessFraction>0. ? thicknessFraction : 0. ;
00191 thicknessFraction = thicknessFraction<1. ? thicknessFraction : 1. ;
00192
00193 double xDriftDueToMagField
00194 = (moduleThickness/2. - segZ)*tanLorentzAngleX;
00195 double positionX = segX + xDriftDueToMagField;
00196
00197 return positionX;
00198
00199 }