CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/SimCalorimetry/HcalSimAlgos/src/HcalSiPM.cc

Go to the documentation of this file.
00001 #include "SimCalorimetry/HcalSimAlgos/interface/HcalSiPM.h"
00002 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00003 #include "FWCore/ServiceRegistry/interface/Service.h"
00004 
00005 #include <cmath>
00006 
00007 using std::vector;
00008 //345678911234567892123456789312345678941234567895123456789612345678971234567898
00009 HcalSiPM::HcalSiPM(int nCells, double tau) :
00010   theCellCount(nCells), theSiPM(nCells,1.), theTauInv(1.0/tau),
00011   theCrossTalk(0.), theTempDep(0.), theLastHitTime(-1.),
00012   theRndGauss(0), theRndPoisson(0), theRndFlat(0) {
00013 
00014   assert(theCellCount>0);
00015   resetSiPM();
00016 }
00017 
00018 HcalSiPM::~HcalSiPM() {
00019   delete theRndGauss;
00020   delete theRndPoisson;
00021   delete theRndFlat;
00022 }
00023 
00024 int HcalSiPM::hitCells(unsigned int photons, unsigned int integral) const {
00025   //don't need to do zero or negative photons.
00026   if (photons < 1) return 0;
00027   if (integral >= theCellCount) return 0;
00028 
00029   if (theRndGauss == 0) {
00030     //random number generator setup
00031     edm::Service<edm::RandomNumberGenerator> rng;
00032     if ( ! rng.isAvailable()) {
00033       throw cms::Exception("Configuration")
00034         << "HcalSiPM requires the RandomNumberGeneratorService\n"
00035         "which is not present in the configuration file.  "
00036         "You must add the service\n"
00037         "in the configuration file or remove the modules that require it.";
00038     }
00039 
00040     CLHEP::HepRandomEngine& engine = rng->getEngine();
00041     theRndGauss = new CLHEP::RandGaussQ(engine);
00042     theRndPoisson = new CLHEP::RandPoissonQ(engine);
00043     theRndFlat = new CLHEP::RandFlat(engine);
00044   }
00045 
00046   //normalize by theCellCount to remove dependency on SiPM size and pixel density.
00047   if ((theCrossTalk > 0.) && (theCrossTalk < 1.))
00048     photons += theRndPoisson->fire(photons/(1.-theCrossTalk)-photons);
00049   double x(photons/double(theCellCount));
00050   double prehit(integral/double(theCellCount));
00051 
00052   //calculate the width and mean of the distribution for a given x
00053   double mean(1. - std::exp(-x));
00054   double width2(std::exp(-x)*(1-(1+x)*std::exp(-x)));
00055 
00056   //you can't hit more than everything.
00057   if (mean > 1.) mean = 1.;
00058 
00059   //convert back to absolute pixels
00060   mean *= (1-prehit)*theCellCount;
00061   width2 *= (1-prehit)*theCellCount;
00062 
00063   double npe;
00064   while (true) {
00065     npe = theRndGauss->fire(mean, std::sqrt(width2 + (mean*prehit)));
00066     if ((npe > -0.5) && (npe <= theCellCount-integral))
00067       return int(npe + 0.5);
00068   }
00069 }
00070 
00071 double HcalSiPM::hitCells(unsigned int pes, double tempDiff, 
00072                           double photonTime) {
00073   // response to light impulse with pes input photons.  The return is the number
00074   // of micro-pixels hit.  If a fraction other than 0. is supplied then the
00075   // micro-pixel doesn't fully discharge.  The tempDiff is the temperature 
00076   // difference from nominal and is used to modify the relative strength of a
00077   // hit pixel.  Pixels which are fractionally charged return a fractional
00078   // number of hit pixels.
00079 
00080   if (theRndGauss == 0) {
00081     //random number generator setup
00082     edm::Service<edm::RandomNumberGenerator> rng;
00083     if ( ! rng.isAvailable()) {
00084       throw cms::Exception("Configuration")
00085         << "HcalSiPM requires the RandomNumberGeneratorService\n"
00086         "which is not present in the configuration file.  "
00087         "You must add the service\n"
00088         "in the configuration file or remove the modules that require it.";
00089     }
00090 
00091     CLHEP::HepRandomEngine& engine = rng->getEngine();
00092     theRndGauss = new CLHEP::RandGaussQ(engine);
00093     theRndPoisson = new CLHEP::RandPoissonQ(engine);
00094     theRndFlat = new CLHEP::RandFlat(engine);
00095   }
00096 
00097   if ((theCrossTalk > 0.) && (theCrossTalk < 1.))
00098     pes += theRndPoisson->fire(pes/(1. - theCrossTalk) - pes);
00099 
00100   unsigned int pixel;
00101   double sum(0.), hit(0.);
00102   for (unsigned int pe(0); pe < pes; ++pe) {
00103     pixel = theRndFlat->fireInt(theCellCount);
00104     hit = (theSiPM[pixel] < 0.) ? 1.0 :
00105       (cellCharge(photonTime - theSiPM[pixel]));
00106     sum += hit*(1 + (tempDiff*theTempDep));
00107     theSiPM[pixel] = photonTime;
00108   }
00109 
00110   theLastHitTime = photonTime;
00111 
00112   return sum;
00113 }
00114 
00115 double HcalSiPM::totalCharge(double time) const {
00116   // sum of the micro-pixels.  NP is a fully charged device.
00117   // 0 is a fullly depleted device.
00118   double tot(0.), hit(0.);
00119   for(unsigned int i=0; i<theCellCount; ++i)  {
00120     hit = (theSiPM[i] < 0.) ? 1. : cellCharge(time - theSiPM[i]);
00121     tot += hit;
00122   }
00123   return tot;
00124 }
00125 
00126 // void HcalSiPM::recoverForTime(double time, double dt) {
00127 //   // apply the RC recover model to the pixels for time.  If dt is not
00128 //   // positive then tau/5 will be used for dt.
00129 //   if (dt <= 0.)
00130 //     dt = 1.0/(theTauInv*5.);
00131 //   for (double t = 0; t < time; t += dt) {
00132 //     expRecover(dt);
00133 //   }
00134 // }
00135 
00136 void HcalSiPM::setNCells(int nCells) {
00137   assert(nCells>0);
00138   theCellCount = nCells;
00139   theSiPM.resize(nCells);
00140   resetSiPM();
00141 }
00142 
00143 void HcalSiPM::setCrossTalk(double xTalk) {
00144   // set the cross-talk probability
00145 
00146   if((xTalk < 0) || (xTalk >= 1)) {
00147     theCrossTalk = 0.;
00148   } else {
00149     theCrossTalk = xTalk;
00150   }   
00151 
00152 }
00153 
00154 void HcalSiPM::setTemperatureDependence(double dTemp) {
00155   // set the temperature dependence
00156   theTempDep = dTemp;
00157 }
00158 
00159 void HcalSiPM::initRandomEngine(CLHEP::HepRandomEngine& engine) {
00160   if(theRndGauss) delete theRndGauss;
00161   theRndGauss = new CLHEP::RandGaussQ(engine);
00162   if(theRndPoisson) delete theRndPoisson;
00163   theRndPoisson = new CLHEP::RandPoissonQ(engine);
00164   if(theRndFlat) delete theRndFlat;
00165   theRndFlat = new CLHEP::RandFlat(engine);
00166 }
00167 
00168 // void HcalSiPM::expRecover(double dt) {
00169 //   // recover each micro-pixel using the RC model.  For this to work well.
00170 //   // dt << tau (typically dt = 0.2*tau or less)
00171 //   double newval;
00172   
00173 //   for (unsigned int i=0; i<theCellCount; ++i) {
00174 //     if (theSiPM[i] < 0.999) {
00175 //       newval = theSiPM[i] + (1 - theSiPM[i])*dt*theTauInv;
00176 //       theSiPM[i] = (newval > 0.99) ? 1.0 : newval;
00177 //   }
00178 // }
00179 
00180 double HcalSiPM::cellCharge(double deltaTime) const {
00181   if (deltaTime <= 0.) return 0.;
00182   if (deltaTime > 10./theTauInv) return 1.;
00183   double result(1. - std::exp(-deltaTime*theTauInv));
00184   return (result > 0.99) ? 1.0 : result;
00185 }