CMS 3D CMS Logo

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