CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch13/src/SimRomanPot/SimFP420/src/ChargeDividerFP420.cc

Go to the documentation of this file.
00001 
00002 // File: ChargeDividerFP420
00003 // Date: 12.2006
00004 // Description: ChargeDividerFP420  for FP420
00005 // Modifications: std::
00007 #include "SimRomanPot/SimFP420/interface/ChargeDividerFP420.h"
00008 #include "DataFormats/GeometryVector/interface/LocalPoint.h"
00009 #include "DataFormats/GeometryVector/interface/LocalVector.h"
00010 
00011 //#include "SimDataFormats/TrackingHit/interface/PSimHit.h"
00012 //#include "SimDataFormats/TrackingHit/interface/PSimHitContainer.h"
00013 
00014 using namespace std;
00015 #include<vector>
00016 
00017 // unpacking variable - zside - Left or Right planes
00018 
00019 //DigitizerFP420::DigitizerFP420(const edm::ParameterSet& conf):conf_(conf),stripDigitizer_(new FP420DigiMain(conf)) 
00020 ChargeDividerFP420::ChargeDividerFP420(double pit, double az420, double azD2, double azD3,int ver){
00021 
00022   verbosity=ver;
00023   //                           pit - is really moduleThickness here !!!
00024   if(verbosity>0) {
00025     std::cout << "ChargeDividerFP420.h: constructor" << std::endl;
00026     std::cout << "peakMode = " << peakMode << "fluctuateCharge=   "<< fluctuateCharge <<  "chargedivisionsPerHit = "  << chargedivisionsPerHit << "deltaCut=   "<< deltaCut << std::endl;
00027   }
00028   // Initialization:
00029   theFP420NumberingScheme = new FP420NumberingScheme();
00030   
00031   
00032   // Run APV in peak instead of deconvolution mode, which degrades the time resolution
00033   //  peakMode=true ; //     APVpeakmode
00034   peakMode=false; //  peakMode=true -->  APVconvolutionmode
00035   decoMode=false;//  decoMode=true -->  deconvolution mode
00036   // Enable interstrip Landau fluctuations within a cluster.
00037   fluctuateCharge=true;   
00038   
00039   // Number of segments per strip into which charge is divided during simulation.
00040   // If large the precision of simulation improves.
00041   chargedivisionsPerHit=10; // = or =20
00042   
00043   // delta cutoff in MeV, has to be same as in OSCAR (0.120425 MeV corresponding // to 100um range for electrons)
00044   //SimpleConfigurable<double>  ChargeDividerFP420::deltaCut(0.120425,
00045   deltaCut=0.120425;  //  DeltaProductionCut
00046   
00047   pitchcur= pit;// pitchcur - is really moduleThickness here !!!
00048   
00049   // but position before Stations:
00050   z420 = az420;  // dist between centers of 1st and 2nd stations
00051   zD2 = azD2;  // dist between centers of 1st and 2nd stations
00052   zD3 = azD3;  // dist between centers of 1st and 3rd stations
00053   
00054   
00055   
00056   //                                                                                                                           .
00057   //                                                                                                                           .
00058   //  -300     -209.2             -150              -90.8                        0                                           +300
00059   //                                                                                                                           .
00060   //            X  | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | X                        station                                          .
00061   //                   8*13.3+ 2*6 = 118.4                                    center                                           .
00062   //                                                                                                                           .
00063   //zStationBegPos[0] = -150. - (118.4+10.)/2 + z420; // 10. -arbitrary
00064   zStationBegPos[0] = -40. + z420; // 5 superplanes per station 79.7mm: -40.- left edge of Station
00065   zStationBegPos[1] = zStationBegPos[0]+zD2;
00066   zStationBegPos[2] = zStationBegPos[0]+zD3;
00067   zStationBegPos[3] = zStationBegPos[0]+2*zD3;
00068   
00069 }
00070 
00071 // Virtual destructor needed.
00072 ChargeDividerFP420::~ChargeDividerFP420() { 
00073   //  if(verbosity>0) {
00074   //    std::cout << "Destroying a ChargeDividerFP420" << std::endl;
00075   //  }
00076   delete theFP420NumberingScheme;
00077   
00078 }  
00079 CDividerFP420::ionization_type 
00080 ChargeDividerFP420::divide(
00081                            const PSimHit& hit, const double& pitchcur) {
00082   // !!!
00083   //                                       pitchcur - is really moduleThickness here !!!
00084   // !!!
00085   
00086   
00087   
00088   // sign "-" mean not the same as "+" for middle point !!!
00089   //  G4ThreeVector direction = hit.getExitLocalP() - hit.getEntryLocalP();
00090   LocalVector direction = hit.exitPoint() - hit.entryPoint();
00091   //   G4ThreeVector direction = hit.exitPoint() - hit.entryPoint();
00092   
00093   //  LocalVector direction = hit.exitPoint() - hit.entryPoint();
00094   // direction.mag() - length or (size of path) of the hit; direction/direction.mag() - cosines of direction
00095   
00096   if(verbosity>0) {
00097     std::cout << " CDividerFP420::ChargeDividerFP420:divide: direction= " << direction << std::endl;
00098     std::cout << " CDividerFP420::ChargeDividerFP420:divide: direction.mag = " << direction.mag() << std::endl;
00099     std::cout << " obtained as ExitLocalP = " << hit.exitPoint() << "  -  "<<  "  EntryLocalP = "  << hit.entryPoint() << std::endl;
00100     std::cout << "  pitchcur= " << pitchcur << std::endl;
00101     std::cout << "  peakMode = " << peakMode << "  decoMode = " << decoMode << "  fluctuateCharge=   "<< fluctuateCharge <<  "  chargedivisionsPerHit = "  << chargedivisionsPerHit << "  deltaCut=   "<< deltaCut << std::endl;
00102   }
00103   
00104   int NumberOfSegmentation =  
00105     
00106     //     (int)(1+chargedivisionsPerHit*fabs(direction.x())/pitchcur); // equidistant in X
00107     //    (int)(1+chargedivisionsPerHit*fabs(direction.z())/pitchcur); // equidistant in Z, but why?
00108     
00109     (int)(1+chargedivisionsPerHit*direction.mag()/pitchcur); // equidistant over hit path
00110   
00111   
00112   if(verbosity>0) {
00113     std::cout << "NumberOfSegmentation= " << NumberOfSegmentation << std::endl;
00114   }
00115   
00116   float eLoss = hit.energyLoss();  // Eloss in GeV
00117   //  float eLoss = hit.getEnergyLoss();  // Eloss in GeV
00118   
00119   if(verbosity>0) {
00120     std::cout << "CDividerFP420::ChargeDividerFP420:divide: eLoss=  " << eLoss << std::endl;
00121   }
00122   
00123   //
00124   //     return the energyLoss weighted CR-RC shape peaked at t0.(PeakShape)
00125   //     return the energyLoss weighted with a gaussian centered at t0 (DeconvolutionShape)
00126   float decSignal = TimeResponse(hit);
00127   if(verbosity>0) {
00128     std::cout << "CDividerFP420::ChargeDividerFP420:divide: decSignal=  " << decSignal << std::endl;
00129   }
00130   
00131   ionization_type _ionization_points;
00132   
00133   _ionization_points.resize(NumberOfSegmentation);
00134   
00135   float energy;
00136   
00137   // Fluctuate charge in track subsegments
00138   float* eLossVector = new float[NumberOfSegmentation];
00139   
00140   
00141   if(verbosity>0) {
00142     std::cout << "CDividerFP420::ChargeDividerFP420:divide:  resize done; then, fluctuateCharge ? = " << fluctuateCharge << std::endl;
00143   }
00144   if( fluctuateCharge ) {
00145     //    int pid = hit.getParticleType();
00146     //    float momentum = hit.getPabs();
00147     int pid = hit.particleType();
00148     float momentum = hit.pabs();
00149     float length = direction.mag();  // length or (size of path) of the hit;
00150     
00151     if(verbosity>0) {
00152       std::cout << "pid= " << pid << "momentum= " << momentum << "eLoss= " << eLoss << "length= " << length << std::endl;
00153     }
00154     fluctuateEloss(pid, momentum, eLoss, length, NumberOfSegmentation, eLossVector);   
00155   }
00156   
00157   for ( int i = 0; i != NumberOfSegmentation; ++i) {
00158     if( fluctuateCharge ) {
00159       energy=eLossVector[i]*decSignal/eLoss;
00160       EnergySegmentFP420 edu(energy,hit.entryPoint()+float((i+0.5)/NumberOfSegmentation)*direction);//take energy value from vector eLossVector  
00161       //   EnergySegmentFP420 edu(energy,hit.getEntryLocalP()+float((i+0.5)/NumberOfSegmentation)*direction);//take energy value from vector eLossVector  
00162       _ionization_points[i] = edu; //save
00163     }else{
00164       energy=decSignal/float(NumberOfSegmentation);
00165       EnergySegmentFP420 edu(energy,hit.entryPoint()+float((i+0.5)/NumberOfSegmentation)*direction);//take energy value from eLoss average over n.segments 
00166       // EnergySegmentFP420 edu(energy,hit.getEntryLocalP()+float((i+0.5)/NumberOfSegmentation)*direction);//take energy value from eLoss average over n.segments 
00167       _ionization_points[i] = edu; //save
00168     }
00169   }
00170   
00171   if(verbosity>0) {
00172     std::cout << "CDividerFP420::ChargeDividerFP420:divide:  !!!  RESULT !!!" << std::endl;
00173     std::cout <<  " _ionization_points size = " << _ionization_points.size() << std::endl;
00174     for(unsigned int i = 0; i < _ionization_points.size(); ++i ) {
00175       std::cout <<  " eLossVector[i] i = " << i << eLossVector[i] << std::endl;
00176     }
00177   }
00178   
00179   delete[] eLossVector;
00180   return _ionization_points;
00181 }
00182 
00183 void ChargeDividerFP420::fluctuateEloss(int pid, float particleMomentum, 
00184                                         float eloss, float length, 
00185                                         int NumberOfSegs,float elossVector[]) {
00186   
00187   // Get dedx for this track
00188   float dedx;
00189   
00190   if(verbosity>0) {
00191     std::cout << "fluctuateEloss: eloss=  " << eloss << "length=  " << length << "NumberOfSegs=  " << NumberOfSegs << std::endl;
00192   }
00193   if( length > 0.) dedx = eloss/length;
00194   else dedx = eloss;
00195   
00196   //  double particleMass = 139.57; // Mass in MeV, Assume pion
00197   double particleMass = 938.271; // Mass in MeV, Assume proton   ----  AZ
00198   //  if( particleTable->getParticleData(pid) ) {  // Get mass from the PDTable
00199   //    particleMass = 1000. * particleTable->getParticleData(pid)->mass(); //Conv. GeV to MeV
00200   //  }
00201   pid = abs(pid);
00202   if(pid==11) particleMass = 0.511;         // Mass in MeV
00203   else if(pid==13) particleMass = 105.658;
00204   else if(pid==211) particleMass = 139.570;
00205   //  else if(pid==2212) particleMass = 938.271;
00206   
00207   float segmentLength = length/NumberOfSegs;
00208   
00209   // Generate charge fluctuations.
00210   float de=0.;
00211   float sum=0.;
00212   double segmentEloss = (1000.*eloss)/NumberOfSegs; //eloss in MeV
00213   if(verbosity>0) {
00214     std::cout << "segmentLength=  " << segmentLength << "segmentEloss=  " << segmentEloss << std::endl;
00215   }
00216   
00217   for (int i=0;i<NumberOfSegs;++i) {
00218     // The G4 routine needs momentum in MeV, mass in Mev, delta-cut in MeV,
00219     // track segment length in mm(!!!), segment eloss in MeV 
00220     // Returns fluctuated eloss in MeV
00221     //    double deltaCutoff = deltaCut.value(); // the cutoff is sometimes redefined inside, so fix it.
00222     double deltaCutoff = deltaCut;
00223     de = fluctuate.SampleFluctuations(double(particleMomentum*1000.),
00224                                       particleMass, deltaCutoff, 
00225                                       double(segmentLength),
00226                                       segmentEloss )/1000.; //convert to GeV
00227     elossVector[i]=de;
00228     sum +=de;
00229   }
00230   
00231   if(verbosity>0) {
00232     std::cout << "sum=  " << sum << std::endl;
00233   }
00234   if(sum>0.) {  // If fluctuations give eloss>0.
00235     // Rescale to the same total eloss
00236     float ratio = eloss/sum;
00237     for (int ii=0;ii<NumberOfSegs;++ii) elossVector[ii]= ratio*elossVector[ii];
00238   } else {  // If fluctuations gives 0 eloss
00239     float averageEloss = eloss/NumberOfSegs;
00240     for (int ii=0;ii<NumberOfSegs;++ii) elossVector[ii]= averageEloss; 
00241   }
00242   return;
00243 }
00244 
00245 float ChargeDividerFP420::TimeResponse( const PSimHit& hit ) {
00246   if (peakMode) {
00247     
00248     if(verbosity>0) {
00249       std::cout << "ChargeDividerFP420:TimeResponse: call of PeakShape" << std::endl;
00250     }
00251     return this->PeakShape( hit );
00252   } else if (decoMode) {
00253     
00254     if(verbosity>0) {
00255       std::cout << "ChargeDividerFP420:TimeResponse: call of DeconvolutionShape" << std::endl;
00256     }
00257     return this->DeconvolutionShape( hit );
00258   } else {
00259     
00260     if(verbosity>0) {
00261       std::cout << "ChargeDividerFP420:TimeResponse: no any  Shape" << std::endl;
00262     }
00263     //    return hit.getEnergyLoss();
00264     return hit.energyLoss();
00265     
00266   }
00267 }
00268 float ChargeDividerFP420::PeakShape(const PSimHit& hit){
00269   // 
00270   // Aim:     return the energyLoss weighted CR-RC shape peaked at t0.
00271   // 
00272   
00273   //   float xEntry = hit.getX() - hit.getVx();
00274   //  float yEntry = hit.getY() - hit.getVy();
00275   //  float zEntry = hit.getZ() - hit.getVz();
00276   float xEntry = 0.5;
00277   float yEntry = 0.5;
00278   float zEntry = 1000.;
00279   
00280   // unsigned int unitID = hit.getUnitID();
00281   unsigned int unitID = hit.detUnitId();
00282   //      int sScale = 20;
00283   int det, zside, sector, zmodule;
00284   FP420NumberingScheme::unpackFP420Index(unitID, det, zside, sector, zmodule);
00285   // intindex is a continues numbering of FP420
00286   //      int zScale=2;  unsigned int intindex = sScale*(sector - 1)+zScale*(zmodule - 1)+zside;
00287   //     int zScale=10; unsigned int intindex = sScale*(sector - 1)+zScale*(zside - 1)+zmodule;
00288   
00289   float RRR      = sqrt(xEntry*xEntry + yEntry*yEntry + zEntry*zEntry);
00290   float costheta = zEntry / RRR ;
00291   //  float theta    = acos(min(max(costheta,float(-1.)),float(1.)));
00292   //  float dist = hit.det().position().mag();
00293   //  float dist = hit.localPosition().mag();//AZ
00294   //  float dist = hit.getEntry().mag();
00295   //  float dist = hit.getEntryLocalP().mag();
00296   float dist     = (zStationBegPos[sector-1] - 420000.) / costheta;
00297   //  float dist     = (zStationBegPos[sector-1] - hit.getVz()) / costheta;
00298   dist     = dist/10.;// mm  --> cm as light velocity = 30 cm/ns
00299   
00300   if(verbosity>0) {
00301     std::cout << "sector=" << sector << std::endl;
00302     std::cout << "zmodule=" << zmodule << std::endl;
00303     std::cout << "zStationBegPos[sector-1]=" << zStationBegPos[sector-1] << std::endl;
00304     std::cout << "RRR=" << RRR << std::endl;
00305     std::cout << "costheta=" << costheta << std::endl;
00306     std::cout << "unitID=" << unitID << std::endl;
00307     //std::cout << "thetaEntry=" << thetaEntry << std::endl;
00308     //std::cout << "my theta=" << theta*180./3.1415927 << std::endl;
00309     std::cout << "dist found =" << dist << std::endl;
00310   }
00311   
00312   // Time when read out relative to time hit produced.
00313   float t0 = dist/30.;  // light velocity = 30 cm/ns
00314   float SigmaShape = 52.17; 
00315   //  float tofNorm = (hit.getTof() - t0)/SigmaShape;
00316   float tofNorm = (hit.tof() - t0)/SigmaShape;
00317   
00318   float readTimeNorm = -tofNorm;
00319   // return the energyLoss weighted with CR-RC shape peaked at t0.
00320   
00321   if(verbosity>0) {
00322     std::cout << "ChargeDividerFP420:PeakShape::dist=" << dist << std::endl;
00323     std::cout << "t0=" <<t0  << std::endl;
00324     std::cout << "hit.getTof()=" << hit.tof() << std::endl;
00325     std::cout << "tofNorm=" << tofNorm << std::endl;
00326     std::cout << "1 + readTimeNorm=" << 1 + readTimeNorm << std::endl;
00327     std::cout << "hit.getEnergyLoss()=" << hit.energyLoss()  << std::endl;
00328     std::cout << "(1 + readTimeNorm)*exp(-readTimeNorm)=" << (1 + readTimeNorm)*exp(-readTimeNorm)  << std::endl;
00329     std::cout << "return=" << hit.energyLoss()*(1 + readTimeNorm)*exp(-readTimeNorm)  << std::endl;
00330   }
00331   if (1 + readTimeNorm > 0) {
00332     //    return hit.energyLoss()*(1 + readTimeNorm)*exp(-readTimeNorm);
00333     return hit.energyLoss()*(1 + readTimeNorm)*exp(-readTimeNorm);
00334     //  return hit.getEnergyLoss()*(1 + readTimeNorm)*exp(-readTimeNorm);
00335   } else {
00336     return 0.;
00337   }
00338 }
00339 
00340 float ChargeDividerFP420::DeconvolutionShape(const PSimHit& hit){
00341   // 
00342   // Aim:     return the energyLoss weighted with a gaussian centered at t0 
00343   // 
00344   //   float xEntry = hit.getX() - hit.getVx();
00345   //  float yEntry = hit.getY() - hit.getVy();
00346   //  float zEntry = hit.getZ() - hit.getVz();
00347   float xEntry = 0.5;
00348   float yEntry = 0.5;
00349   float zEntry = 1000.;
00350   
00351   // unsigned int unitID = hit.getUnitID();
00352   unsigned int unitID = hit.detUnitId();
00353   //      int sScale = 20;
00354   int det, zside, sector, zmodule;
00355   FP420NumberingScheme::unpackFP420Index(unitID, det, zside, sector, zmodule);
00356   // intindex is a continues numbering of FP420
00357   //      int zScale=2;  unsigned int intindex = sScale*(sector - 1)+zScale*(zmodule - 1)+zside;
00358   //     int zScale=10; unsigned int intindex = sScale*(sector - 1)+zScale*(zside - 1)+zmodule;
00359   
00360   float RRR      = sqrt(xEntry*xEntry + yEntry*yEntry + zEntry*zEntry);
00361   float costheta = zEntry / RRR ;
00362   //  float theta    = acos(min(max(costheta,float(-1.)),float(1.)));
00363   //  float dist = hit.det().position().mag();
00364   //  float dist = hit.localPosition().mag();//AZ
00365   //  float dist = hit.getEntry().mag();
00366   //  float dist = hit.getEntryLocalP().mag();
00367   float dist     = (zStationBegPos[sector-1] - 420000.) / costheta;
00368   //  float dist     = (zStationBegPos[sector-1] - hit.getVz()) / costheta;
00369   dist     = dist/10.;// mm  --> cm as light velocity = 30 cm/ns
00370   
00371   if(verbosity>0) {
00372     std::cout << "sector=" << sector << std::endl;
00373     std::cout << "zmodule=" << zmodule << std::endl;
00374     std::cout << "zStationBegPos[sector-1]=" << zStationBegPos[sector-1] << std::endl;
00375     std::cout << "RRR=" << RRR << std::endl;
00376     std::cout << "costheta=" << costheta << std::endl;
00377     std::cout << "unitID=" << unitID << std::endl;
00378     //std::cout << "thetaEntry=" << thetaEntry << std::endl;
00379     //std::cout << "my theta=" << theta*180./3.1415927 << std::endl;
00380     std::cout << "dist found =" << dist << std::endl;
00381   }
00382   
00383   float t0 = dist/30.;  // light velocity = 30 cm/ns
00384   float SigmaShape = 12.; 
00385   //fun/pl 1*exp(-0.5*((0.1/30-x)/0.1)**2) 0. 0.08
00386   //  float SigmaShape = 22.; 
00387   //  float tofNorm = (hit.tof() - t0)/SigmaShape;
00388   float tofNorm = (hit.tof() - t0)/SigmaShape;
00389   // Time when read out relative to time hit produced.
00390   float readTimeNorm = -tofNorm;
00391   // return the energyLoss weighted with a gaussian centered at t0 
00392   //  return hit.energyLoss()*exp(-0.5*readTimeNorm*readTimeNorm);
00393   
00394   if(verbosity>0) {
00395     std::cout << "ChargeDividerFP420:DeconvolutionShape::dist=" << dist << std::endl;
00396     std::cout << "t0=" <<t0  << std::endl;
00397     std::cout << "hit.getTof()=" << hit.tof() << std::endl;
00398     std::cout << "tofNorm=" << tofNorm << std::endl;
00399     std::cout << "hit.getEnergyLoss()=" << hit.energyLoss()  << std::endl;
00400     std::cout << "exp(-0.5*readTimeNorm*readTimeNorm)=" << exp(-0.5*readTimeNorm*readTimeNorm)  << std::endl;
00401     std::cout << "return=" << hit.energyLoss()*exp(-0.5*readTimeNorm*readTimeNorm)  << std::endl;
00402   }
00403   return hit.energyLoss()*exp(-0.5*readTimeNorm*readTimeNorm);
00404   //  return hit.getEnergyLoss();
00405 }
00406