CMS 3D CMS Logo

SiLinearChargeDivider.cc

Go to the documentation of this file.
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   // Run APV in peak instead of deconvolution mode, which degrades the time resolution.
00010   peakMode=conf_.getParameter<bool>("APVpeakmode");
00011   
00012   // APV time resolution
00013   timeResPeak=conf_.getParameter<double>("SigmaShapePeak");
00014   timeResDeco=conf_.getParameter<double>("SigmaShapeDeco");
00015 
00016   // Enable interstrip Landau fluctuations within a cluster.
00017   fluctuateCharge=conf_.getParameter<bool>("LandauFluctuations");
00018   
00019   // Number of segments per strip into which charge is divided during
00020   // simulation. If large, precision of simulation improves.
00021   chargedivisionsPerStrip=conf_.getParameter<int>("chargeDivisionsPerStrip");
00022  
00023   // delta cutoff in MeV, has to be same as in OSCAR (0.120425 MeV corresponding // to 100um range for electrons)
00024   deltaCut=conf_.getParameter<double>("DeltaProductionCut");
00025 
00026   //Offset for digitization during the MTCC and in general for taking cosmic particle
00027   //The value to be used it must be evaluated and depend on the volume defnition used
00028   //for the cosimc generation (Considering only the tracker the value is 11 ns)
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();  // Eloss in GeV
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   // Fluctuate charge in track subsegments
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();  // Track length in Silicon
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);//take energy value from vector eLossVector  
00071       _ionization_points[i] = edu; //save
00072     }else{
00073       energy=decSignal/float(NumberOfSegmentation);
00074       EnergyDepositUnit edu(energy,hit.entryPoint()+float((i+0.5)/NumberOfSegmentation)*direction);//take energy value from eLoss average over n.segments 
00075       _ionization_points[i] = edu; //save
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   // Get dedx for this track
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;              // Mass in MeV, Assume pion
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; // Mass in MeV
00103     }
00104 
00105   //This is a temporary fix for protect from particles with Mass = 0
00106   if(fabs(particleMass)<1.e-6 || pid == 22)
00107     particleMass = 139.57;
00108 
00109   float segmentLength = length/NumberOfSegs;
00110 
00111   // Generate charge fluctuations.
00112   float de=0.;
00113   float sum=0.;
00114   double segmentEloss = (1000.*eloss)/NumberOfSegs; //eloss in MeV
00115   for (int i=0;i<NumberOfSegs;i++) {
00116     // The G4 routine needs momentum in MeV, mass in MeV, delta-cut in MeV,
00117     // track segment length in mm, segment eloss in MeV 
00118     // Returns fluctuated eloss in MeV
00119     // the cutoff is sometimes redefined inside, so fix it.
00120     double deltaCutoff = deltaCut;
00121     de = fluctuate->SampleFluctuations(double(particleMomentum*1000.),
00122                                        particleMass, deltaCutoff, 
00123                                        double(segmentLength*10.),
00124                                        segmentEloss )/1000.; //convert to GeV
00125     elossVector[i]=de;
00126     sum +=de;
00127   }
00128   
00129   if(sum>0.) {  // If fluctuations give eloss>0.
00130     // Rescale to the same total eloss
00131     float ratio = eloss/sum;
00132     for (int ii=0;ii<NumberOfSegs;ii++) elossVector[ii]= ratio*elossVector[ii];
00133   } else {  // If fluctuations gives 0 eloss
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.;  // light velocity = 30 cm/ns
00151   float SigmaShape = timeResPeak; // 52.17 ns from fit made by I.Tomalin to APV25 data presented by M.Raymond at LEB2000 conference.
00152   float tofNorm = (hit.tof() - cosmicShift - t0)/SigmaShape;
00153   // Time when read out relative to time hit produced.
00154   float readTimeNorm = -tofNorm;
00155   // return the energyLoss weighted CR-RC shape peaked at t0.
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.;  // light velocity = 30 cm/ns
00166   float SigmaShape = timeResDeco; // 12.06 ns from fit made by I.Tomalin to APV25 data presented by M.Raymond at LEB2000 conference.
00167   float tofNorm = (hit.tof() - cosmicShift - t0)/SigmaShape;
00168   // Time when read out relative to time hit produced.
00169   float readTimeNorm = -tofNorm;
00170   // return the energyLoss weighted with a gaussian centered at t0 
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   // fix the bug due to  rounding on entry and exit point
00190   thicknessFraction = thicknessFraction>0. ? thicknessFraction : 0. ;
00191   thicknessFraction = thicknessFraction<1. ? thicknessFraction : 1. ;
00192   
00193   double xDriftDueToMagField // Drift along X due to BField
00194     = (moduleThickness/2. - segZ)*tanLorentzAngleX;
00195   double positionX = segX + xDriftDueToMagField;
00196 
00197   return positionX;
00198                      
00199 }

Generated on Tue Jun 9 17:47:53 2009 for CMSSW by  doxygen 1.5.4