CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_4_5_patch3/src/SimCalorimetry/CaloSimAlgos/src/CaloHitResponse.cc

Go to the documentation of this file.
00001 #include "SimCalorimetry/CaloSimAlgos/interface/CaloHitResponse.h" 
00002 #include "SimDataFormats/CaloHit/interface/PCaloHit.h" 
00003 #include "SimCalorimetry/CaloSimAlgos/interface/CaloVSimParameterMap.h"
00004 #include "SimCalorimetry/CaloSimAlgos/interface/CaloSimParameters.h"
00005 #include "SimCalorimetry/CaloSimAlgos/interface/CaloVShape.h"
00006 #include "SimCalorimetry/CaloSimAlgos/interface/CaloShapes.h"
00007 #include "SimCalorimetry/CaloSimAlgos/interface/CaloVHitCorrection.h"
00008 #include "SimCalorimetry/CaloSimAlgos/interface/CaloVHitFilter.h"
00009 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00010 #include "Geometry/CaloGeometry/interface/CaloSubdetectorGeometry.h"
00011 #include "Geometry/CaloGeometry/interface/CaloCellGeometry.h"
00012 #include "FWCore/ServiceRegistry/interface/Service.h"
00013 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00014 #include "CLHEP/Random/RandPoissonQ.h"
00015 #include "CLHEP/Random/RandFlat.h"
00016 #include "FWCore/Utilities/interface/Exception.h"
00017 
00018 #include "CLHEP/Units/GlobalPhysicalConstants.h"
00019 #include "CLHEP/Units/GlobalSystemOfUnits.h" 
00020 #include<iostream>
00021 
00022 
00023 CaloHitResponse::CaloHitResponse(const CaloVSimParameterMap * parametersMap, 
00024                                  const CaloVShape * shape)
00025 : theAnalogSignalMap(),
00026   theParameterMap(parametersMap), 
00027   theShapes(0),  
00028   theShape(shape),
00029   theHitCorrection(0),
00030   thePECorrection(0),
00031   theHitFilter(0),
00032   theGeometry(0),
00033   theRandPoisson(0),
00034   theMinBunch(-10), 
00035   theMaxBunch(10),
00036   thePhaseShift_(1.)
00037 {
00038 }
00039 
00040 
00041 CaloHitResponse::CaloHitResponse(const CaloVSimParameterMap * parametersMap,
00042                                  const CaloShapes * shapes)
00043 : theAnalogSignalMap(),
00044   theParameterMap(parametersMap),
00045   theShapes(shapes),
00046   theShape(0),
00047   theHitCorrection(0),
00048   thePECorrection(0),
00049   theHitFilter(0),
00050   theGeometry(0),
00051   theRandPoisson(0),
00052   theMinBunch(-10),
00053   theMaxBunch(10),
00054   thePhaseShift_(1.)
00055 {
00056 }
00057 
00058 
00059 CaloHitResponse::~CaloHitResponse()
00060 {
00061   delete theRandPoisson;
00062 }
00063 
00064 
00065 void CaloHitResponse::setBunchRange(int minBunch, int maxBunch) {
00066   theMinBunch = minBunch;
00067   theMaxBunch = maxBunch;
00068 }
00069 
00070 
00071 void CaloHitResponse::setRandomEngine(CLHEP::HepRandomEngine & engine)
00072 {
00073   theRandPoisson = new CLHEP::RandPoissonQ(engine);
00074 }
00075 
00076 
00077 void CaloHitResponse::run(MixCollection<PCaloHit> & hits) {
00078 
00079   for(MixCollection<PCaloHit>::MixItr hitItr = hits.begin();
00080       hitItr != hits.end(); ++hitItr)
00081   {
00082     // check the bunch crossing range
00083     if ( hitItr.bunch() < theMinBunch || hitItr.bunch() > theMaxBunch ) 
00084       { continue; }
00085   
00086     add(*hitItr);
00087   } // loop over hits
00088 }
00089 
00090 
00091 void 
00092 CaloHitResponse::add( const PCaloHit& hit )
00093 {
00094   // check the hit time makes sense
00095   if ( isnan(hit.time()) ) { return; }
00096 
00097   // maybe it's not from this subdetector
00098   if(theHitFilter == 0 || theHitFilter->accepts(hit)) {
00099     LogDebug("CaloHitResponse") << hit;
00100     CaloSamples signal( makeAnalogSignal( hit ) ) ;
00101 
00102     bool keep ( keepBlank() ) ;  // here we  check for blank signal if not keeping them
00103     if( !keep )
00104     {
00105        const unsigned int size ( signal.size() ) ;
00106        if( 0 != size )
00107        {
00108           for( unsigned int i ( 0 ) ; i != size ; ++i )
00109           {
00110              keep = keep || signal[i] > 1.e-7 ;
00111           }
00112        }
00113     }
00114     LogDebug("CaloHitResponse") << signal;
00115     if( keep ) add(signal);
00116   }
00117 }
00118 
00119 
00120 void CaloHitResponse::add(const CaloSamples & signal)
00121 {
00122   DetId id(signal.id());
00123   CaloSamples * oldSignal = findSignal(id);
00124   if (oldSignal == 0) {
00125     theAnalogSignalMap[id] = signal;
00126   } else  {
00127     // need a "+=" to CaloSamples
00128     int sampleSize =  oldSignal->size();
00129     assert(sampleSize == signal.size());
00130     assert(signal.presamples() == oldSignal->presamples());
00131 
00132     for(int i = 0; i < sampleSize; ++i) {
00133       (*oldSignal)[i] += signal[i];
00134     }
00135   }
00136 }
00137 
00138 
00139 CaloSamples CaloHitResponse::makeAnalogSignal(const PCaloHit & inputHit) const {
00140 
00141   // see if we need to correct the hit 
00142   PCaloHit hit = inputHit;
00143 
00144   if(theHitCorrection != 0) {
00145     theHitCorrection->correct(hit);
00146   }
00147 
00148   DetId detId(hit.id());
00149   const CaloSimParameters & parameters = theParameterMap->simParameters(detId);
00150 
00151   double signal = analogSignalAmplitude(hit, parameters);
00152 
00153   double jitter = hit.time() - timeOfFlight(detId);
00154 
00155   const CaloVShape * shape = theShape;
00156   if(!shape) {
00157     shape = theShapes->shape(detId);
00158   }
00159   // assume bins count from zero, go for center of bin
00160   const double tzero = ( shape->timeToRise()
00161                          + parameters.timePhase() 
00162                          - jitter 
00163                          - BUNCHSPACE*( parameters.binOfMaximum()
00164                                         - thePhaseShift_          ) ) ;
00165   double binTime = tzero;
00166 
00167   CaloSamples result(makeBlankSignal(detId));
00168 
00169   for(int bin = 0; bin < result.size(); bin++) {
00170     result[bin] += (*shape)(binTime)* signal;
00171     binTime += BUNCHSPACE;
00172   }
00173   return result;
00174 } 
00175 
00176 
00177 double CaloHitResponse::analogSignalAmplitude(const PCaloHit & hit, const CaloSimParameters & parameters) const {
00178 
00179   if(!theRandPoisson)
00180   {
00181     edm::Service<edm::RandomNumberGenerator> rng;
00182     if ( ! rng.isAvailable()) {
00183       throw cms::Exception("Configuration")
00184         << "CaloHitResponse requires the RandomNumberGeneratorService\n"
00185         "which is not present in the configuration file.  You must add the service\n"
00186         "in the configuration file or remove the modules that require it.";
00187     }
00188     theRandPoisson = new CLHEP::RandPoissonQ(rng->getEngine());
00189   }
00190 
00191   // OK, the "energy" in the hit could be a real energy, deposited energy,
00192   // or pe count.  This factor converts to photoelectrons
00193   DetId detId(hit.id());
00194   double npe = hit.energy() * parameters.simHitToPhotoelectrons(detId);
00195   // do we need to doPoisson statistics for the photoelectrons?
00196   if(parameters.doPhotostatistics()) {
00197     npe = theRandPoisson->fire(npe);
00198   }
00199   if(thePECorrection) npe = thePECorrection->correctPE(detId, npe);
00200   return npe;
00201 }
00202 
00203 
00204 CaloSamples * CaloHitResponse::findSignal(const DetId & detId) {
00205   CaloSamples * result = 0;
00206   AnalogSignalMap::iterator signalItr = theAnalogSignalMap.find(detId);
00207   if(signalItr == theAnalogSignalMap.end()) {
00208      result = 0;
00209   } 
00210   else {
00211      result = &(signalItr->second);
00212   }
00213   return result;
00214 }
00215 
00216 
00217 CaloSamples CaloHitResponse::makeBlankSignal(const DetId & detId) const {
00218   const CaloSimParameters & parameters = theParameterMap->simParameters(detId);
00219   CaloSamples result(detId, parameters.readoutFrameSize());
00220   result.setPresamples(parameters.binOfMaximum()-1);
00221   return result;
00222 }
00223 
00224 
00225 double CaloHitResponse::timeOfFlight(const DetId & detId) const {
00226   // not going to assume there's one of these per subdetector.
00227   // Take the whole CaloGeometry and find the right subdet
00228   double result = 0.;
00229   if(theGeometry == 0) {
00230     edm::LogWarning("CaloHitResponse") << "No Calo Geometry set, so no time of flight correction";
00231   } 
00232   else {
00233     const CaloCellGeometry* cellGeometry = theGeometry->getSubdetectorGeometry(detId)->getGeometry(detId);
00234     if(cellGeometry == 0) {
00235        edm::LogWarning("CaloHitResponse") << "No Calo cell found for ID"
00236          << detId.rawId() << " so no time-of-flight subtraction will be done";
00237     }
00238     else {
00239       double distance = cellGeometry->getPosition().mag();
00240       result =  distance * cm / c_light; // Units of c_light: mm/ns
00241     }
00242   }
00243   return result;
00244 }
00245 
00246