CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/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 "DataFormats/HcalDetId/interface/HcalDetId.h"
00013 #include "FWCore/ServiceRegistry/interface/Service.h"
00014 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00015 #include "CLHEP/Random/RandPoissonQ.h"
00016 #include "CLHEP/Random/RandFlat.h"
00017 #include "FWCore/Utilities/interface/Exception.h"
00018 #include "FWCore/Utilities/interface/isFinite.h"
00019 
00020 #include "CLHEP/Units/GlobalPhysicalConstants.h"
00021 #include "CLHEP/Units/GlobalSystemOfUnits.h" 
00022 
00023 #include<iostream>
00024 
00025 CaloHitResponse::CaloHitResponse(const CaloVSimParameterMap * parametersMap, 
00026                                  const CaloVShape * shape)
00027 : theAnalogSignalMap(),
00028   theParameterMap(parametersMap), 
00029   theShapes(0),  
00030   theShape(shape),  
00031   theHitCorrection(0),
00032   thePECorrection(0),
00033   theHitFilter(0),
00034   theGeometry(0),
00035   theRandPoisson(0),
00036   theMinBunch(-10), 
00037   theMaxBunch(10),
00038   thePhaseShift_(1.),
00039   changeScale(false) {}
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   changeScale(false) {}
00056 
00057 CaloHitResponse::~CaloHitResponse() {
00058   delete theRandPoisson;
00059 }
00060 
00061 void CaloHitResponse::initHBHEScale() {
00062 #ifdef ChangeHcalEnergyScale
00063   for (int ij=0; ij<100; ij++) {
00064     for (int jk=0; jk<72; jk++) {       
00065       for (int kl=0; kl<4; kl++) {
00066         hcal_en_scale[ij][jk][kl] = 1.0;
00067       }
00068     }
00069   }
00070 #endif
00071 }
00072 
00073 void CaloHitResponse::setHBHEScale(std::string & fileIn) {
00074   
00075   ifstream infile(fileIn.c_str());
00076   LogDebug("CaloHitResponse") << "Reading from " << fileIn;
00077 #ifdef ChangeHcalEnergyScale
00078   if (!infile.is_open()) {
00079     edm::LogError("CaloHitResponse") << "** ERROR: Can't open '" << fileIn << "' for the input file";
00080   } else {
00081     int     eta, phi, depth;
00082     double  cFactor;
00083     while(1) {
00084       infile >> eta >> phi >> depth >> cFactor;
00085       if (!infile.good()) break;
00086       hcal_en_scale[eta][phi][depth] = cFactor;
00087       //      LogDebug("CaloHitResponse") << "hcal_en_scale[" << eta << "][" << phi << "][" << depth << "] = " << hcal_en_scale[eta][phi][depth];
00088     }
00089     infile.close();
00090   }
00091   changeScale = true;
00092 #endif
00093 }
00094 
00095 void CaloHitResponse::setBunchRange(int minBunch, int maxBunch) {
00096   theMinBunch = minBunch;
00097   theMaxBunch = maxBunch;
00098 }
00099 
00100 
00101 void CaloHitResponse::setRandomEngine(CLHEP::HepRandomEngine & engine) {
00102   theRandPoisson = new CLHEP::RandPoissonQ(engine);
00103 }
00104 
00105 
00106 void CaloHitResponse::run(MixCollection<PCaloHit> & hits) {
00107 
00108   for(MixCollection<PCaloHit>::MixItr hitItr = hits.begin();
00109       hitItr != hits.end(); ++hitItr) {
00110     if(withinBunchRange(hitItr.bunch())) {
00111       add(*hitItr);
00112     } // loop over hits
00113   }
00114 }
00115 
00116 void CaloHitResponse::add( const PCaloHit& hit ) {
00117   // check the hit time makes sense
00118   if ( edm::isNotFinite(hit.time()) ) { return; }
00119 
00120   // maybe it's not from this subdetector
00121   if(theHitFilter == 0 || theHitFilter->accepts(hit)) {
00122     LogDebug("CaloHitResponse") << hit;
00123     CaloSamples signal( makeAnalogSignal( hit ) ) ;
00124 
00125     bool keep ( keepBlank() ) ;  // here we  check for blank signal if not keeping them
00126     if( !keep )
00127     {
00128        const unsigned int size ( signal.size() ) ;
00129        if( 0 != size )
00130        {
00131           for( unsigned int i ( 0 ) ; i != size ; ++i )
00132           {
00133              keep = keep || signal[i] > 1.e-7 ;
00134           }
00135        }
00136     }
00137     LogDebug("CaloHitResponse") << signal;
00138     if( keep ) add(signal);
00139   }
00140 }
00141 
00142 
00143 void CaloHitResponse::add(const CaloSamples & signal)
00144 {
00145   DetId id(signal.id());
00146   CaloSamples * oldSignal = findSignal(id);
00147   if (oldSignal == 0) {
00148     theAnalogSignalMap[id] = signal;
00149   } else  {
00150     // need a "+=" to CaloSamples
00151     int sampleSize =  oldSignal->size();
00152     assert(sampleSize == signal.size());
00153     assert(signal.presamples() == oldSignal->presamples());
00154 
00155     for(int i = 0; i < sampleSize; ++i) {
00156       (*oldSignal)[i] += signal[i];
00157     }
00158   }
00159 }
00160 
00161 
00162 CaloSamples CaloHitResponse::makeAnalogSignal(const PCaloHit & hit) const {
00163 
00164   DetId detId(hit.id());
00165   const CaloSimParameters & parameters = theParameterMap->simParameters(detId);
00166   
00167   double signal = analogSignalAmplitude(detId, hit.energy(), parameters);
00168 
00169   double time = hit.time();
00170   if(theHitCorrection != 0) {
00171     time += theHitCorrection->delay(hit);
00172   }
00173   double jitter = hit.time() - timeOfFlight(detId);
00174 
00175   const CaloVShape * shape = theShape;
00176   if(!shape) {
00177     shape = theShapes->shape(detId);
00178   }
00179   // assume bins count from zero, go for center of bin
00180   const double tzero = ( shape->timeToRise()
00181                          + parameters.timePhase() 
00182                          - jitter 
00183                          - BUNCHSPACE*( parameters.binOfMaximum()
00184                                         - thePhaseShift_          ) ) ;
00185   double binTime = tzero;
00186 
00187   CaloSamples result(makeBlankSignal(detId));
00188 
00189   for(int bin = 0; bin < result.size(); bin++) {
00190     result[bin] += (*shape)(binTime)* signal;
00191     binTime += BUNCHSPACE;
00192   }
00193   return result;
00194 } 
00195 
00196 
00197 double CaloHitResponse::analogSignalAmplitude(const DetId & detId, float energy, const CaloSimParameters & parameters) const {
00198 
00199   if(!theRandPoisson)
00200     {
00201       edm::Service<edm::RandomNumberGenerator> rng;
00202       if ( ! rng.isAvailable()) {
00203         throw cms::Exception("Configuration")
00204           << "CaloHitResponse requires the RandomNumberGeneratorService\n"
00205           "which is not present in the configuration file.  You must add the service\n"
00206           "in the configuration file or remove the modules that require it.";
00207       }
00208       theRandPoisson = new CLHEP::RandPoissonQ(rng->getEngine());
00209     }
00210   
00211   // OK, the "energy" in the hit could be a real energy, deposited energy,
00212   // or pe count.  This factor converts to photoelectrons
00213   //GMA Smeared in photon production it self  
00214   double scl =1.0;
00215 #ifdef ChangeHcalEnergyScale
00216   if (changeScale) {
00217     if (detId.det()==DetId::Hcal ) { 
00218       HcalDetId dId = HcalDetId(detId); 
00219       if (dId.subdet()==HcalBarrel || dId.subdet()==HcalEndcap) { 
00220         int ieta = dId.ieta()+50;
00221         int iphi = dId.iphi()-1;
00222         int idep = dId.depth()-1;
00223         scl = hcal_en_scale[ieta][iphi][idep];
00224         LogDebug("CaloHitResponse") << " ID " << dId << " Scale " << scl;
00225       }
00226     }
00227   } 
00228 #endif
00229   double npe = scl * energy * parameters.simHitToPhotoelectrons(detId);
00230   // do we need to doPoisson statistics for the photoelectrons?
00231   if(parameters.doPhotostatistics()) {
00232     npe = theRandPoisson->fire(npe);
00233   }
00234   if(thePECorrection) npe = thePECorrection->correctPE(detId, npe);
00235   return npe;
00236 }
00237 
00238 
00239 CaloSamples * CaloHitResponse::findSignal(const DetId & detId) {
00240   CaloSamples * result = 0;
00241   AnalogSignalMap::iterator signalItr = theAnalogSignalMap.find(detId);
00242   if(signalItr == theAnalogSignalMap.end()) {
00243     result = 0;
00244   } else {
00245     result = &(signalItr->second);
00246   }
00247   return result;
00248 }
00249 
00250 
00251 CaloSamples CaloHitResponse::makeBlankSignal(const DetId & detId) const {
00252   const CaloSimParameters & parameters = theParameterMap->simParameters(detId);
00253   CaloSamples result(detId, parameters.readoutFrameSize());
00254   result.setPresamples(parameters.binOfMaximum()-1);
00255   return result;
00256 }
00257 
00258 
00259 double CaloHitResponse::timeOfFlight(const DetId & detId) const {
00260   // not going to assume there's one of these per subdetector.
00261   // Take the whole CaloGeometry and find the right subdet
00262   double result = 0.;
00263   if(theGeometry == 0) {
00264     edm::LogWarning("CaloHitResponse") << "No Calo Geometry set, so no time of flight correction";
00265   } 
00266   else {
00267     const CaloCellGeometry* cellGeometry = theGeometry->getSubdetectorGeometry(detId)->getGeometry(detId);
00268     if(cellGeometry == 0) {
00269        edm::LogWarning("CaloHitResponse") << "No Calo cell found for ID"
00270          << detId.rawId() << " so no time-of-flight subtraction will be done";
00271     }
00272     else {
00273       double distance = cellGeometry->getPosition().mag();
00274       result =  distance * cm / c_light; // Units of c_light: mm/ns
00275     }
00276   }
00277   return result;
00278 }
00279 
00280