CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/SimG4CMS/Calo/src/HcalQie.cc

Go to the documentation of this file.
00001 
00002 // File: HcalQie.cc
00003 // Description: Simulation of QIE readout for HCal
00005 
00006 #include "SimG4CMS/Calo/interface/HcalQie.h"
00007 
00008 #include "FWCore/ServiceRegistry/interface/Service.h"
00009 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00010 #include "CLHEP/Random/RandGaussQ.h"
00011 #include "CLHEP/Random/RandPoissonQ.h"
00012 #include "FWCore/Utilities/interface/Exception.h"
00013 #include "CLHEP/Units/GlobalPhysicalConstants.h"
00014 
00015 #include <iostream>
00016 #include <iomanip>
00017 #include <cmath>
00018 
00019 //#define DebugLog
00020 
00021 HcalQie::HcalQie(edm::ParameterSet const & p) {
00022 
00023   //static SimpleConfigurable<double> p1(4.0,   "HcalQie:qToPE");
00024   //static SimpleConfigurable<int>    p2(6,     "HcalQie:BinOfMax");
00025   //static SimpleConfigurable<int>    p3(2,     "HcalQie:SignalBuckets");
00026   //static SimpleConfigurable<int>    p4(0,     "HcalQie:PreSamples");
00027   //static SimpleConfigurable<int>    p5(10,    "HcalQie:NumOfBuckets");
00028   //static SimpleConfigurable<double> p6(0.5,   "HcalQie:SigmaNoise");
00029   //static SimpleConfigurable<double> p7(0.0005,"HcalQie:EDepPerPE");
00030   //static SimpleConfigurable<int>    p8(4,     "HcalQie:BaseLine");
00031 
00032   edm::ParameterSet m_HQ  = p.getParameter<edm::ParameterSet>("HcalQie");
00033   qToPE         = m_HQ.getParameter<double>("qToPE");
00034   binOfMax      = m_HQ.getParameter<int>("BinOfMax");
00035   signalBuckets = m_HQ.getParameter<int>("SignalBuckets");
00036   preSamples    = m_HQ.getParameter<int>("PreSamples");
00037   numOfBuckets  = m_HQ.getParameter<int>("NumOfBuckets");
00038   sigma         = m_HQ.getParameter<double>("SigmaNoise");
00039   eDepPerPE     = m_HQ.getParameter<double>("EDepPerPE");
00040   int bl        = m_HQ.getParameter<int>("BaseLine");
00041 
00042   shape_  = shape();
00043   code_   = code();
00044   charge_ = charge();
00045   if (signalBuckets == 1) {
00046     phase_ = -3; rescale_ = 1.46;
00047   } else if (signalBuckets == 3) {
00048     phase_ = -1; rescale_ = 1.06;
00049   } else if (signalBuckets == 4) {
00050     phase_ =  0; rescale_ = 1.03;
00051   } else {
00052     phase_ = -2; rescale_ = 1.14; signalBuckets = 2;
00053   }
00054   weight_ = weight(binOfMax, signalBuckets, preSamples, numOfBuckets);
00055   baseline= codeToQ(bl);
00056   bmin_   = binOfMax-3;
00057   if (bmin_<0) bmin_ = 0;
00058   if (binOfMax>numOfBuckets) 
00059     bmax_ = numOfBuckets+5;
00060   else 
00061     bmax_ = binOfMax+5;
00062 
00063   edm::LogInfo("HcalSim") << "HcalQie: initialized with binOfMax " << binOfMax 
00064                           << " sample from " << bmin_ << " to " << bmax_ 
00065                           << "; signalBuckets " << signalBuckets 
00066                           << " Baseline/Phase/Scale " << baseline << "/" 
00067                           << phase_ << "/" << rescale_ << "\n"
00068                           <<"                          Noise " << sigma 
00069                           << "fC  fCToPE " << qToPE << " EDepPerPE " 
00070                           << eDepPerPE;
00071 }
00072 
00073 HcalQie::~HcalQie() {
00074   edm::LogInfo("HcalSim") << "HcalQie:: Deleting Qie";
00075 }
00076 
00077 std::vector<double> HcalQie::shape() {
00078 
00079   // pulse shape time constants in ns
00080   const float ts1  = 8.;          // scintillation time constants : 1,2,3
00081   const float ts2  = 10.;           
00082   const float ts3  = 29.3;         
00083   const float thpd = 4.;          // HPD current collection drift time
00084   const float tpre = 5.;          // preamp time constant
00085   
00086   const float wd1 = 2.;           // relative weights of decay exponents 
00087   const float wd2 = 0.7;
00088   const float wd3 = 1.;
00089 
00090   // HPD starts at I and rises to 2I in thpd of time
00091   double norm=0.0;
00092   int j, hpd_siz = (int)(thpd);
00093   std::vector<double> hpd_drift(hpd_siz);
00094   for (j=0; j<hpd_siz; j++) {
00095     double tmp = (double)j + 0.5;
00096     hpd_drift[j] = 1.0 + tmp/thpd;
00097     norm += hpd_drift[j];
00098   }
00099   // normalize integrated current to 1.0
00100   for (j=0; j<hpd_siz; j++) {
00101     hpd_drift[j] /= norm;
00102   }
00103   
00104   // Binkley shape over 6 time constants
00105   int  preamp_siz=(int)(6*tpre);
00106   std::vector<double> preamp(preamp_siz);
00107   norm = 0;
00108   for (j=0; j<preamp_siz; j++) {
00109     double tmp = (double)j + 0.5;
00110     preamp[j]  = tmp*exp(-(tmp*tmp)/(tpre*tpre));
00111     norm += preamp[j];
00112   }
00113   // normalize pulse area to 1.0
00114   for (j=0; j<preamp_siz; j++) {
00115     preamp[j] /= norm;
00116   }
00117 
00118   // ignore stochastic variation of photoelectron emission
00119   // <...>
00120   // effective tile plus wave-length shifter decay time over 4 time constants
00121 
00122   int tmax = 6 * (int)ts3;
00123   std::vector<double> scnt_decay(tmax);
00124   norm = 0;
00125   for (j=0; j<tmax; j++) {
00126     double tmp = (double)j + 0.5;
00127     scnt_decay[j] = wd1*exp(-tmp/ts1) + wd2*exp(-tmp/ts2) + wd3*exp(-tmp/ts3);
00128     norm += scnt_decay[j];
00129   }
00130   // normalize pulse area to 1.0
00131   for (j=0; j<tmax; j++) {
00132     scnt_decay[j] /= norm;
00133   }
00134 
00135   int nsiz = tmax + hpd_siz + preamp_siz + 1;
00136   std::vector<double> pulse(nsiz,0.0);  // zeroing output pulse shape
00137   norm = 0;
00138   int    i, k;
00139   for (i=0; i<tmax; i++) {
00140     int t1 = i; // and ignore jitter from optical path length
00141     for (j=0; j<hpd_siz; j++) {
00142       int t2 = t1 + j;
00143       for (k=0; k<preamp_siz; k++) {
00144         int   t3 = t2 + k;
00145         float tmp = scnt_decay[i]*hpd_drift[j]*preamp[k];
00146         pulse[t3]+= tmp;
00147         norm     += tmp;
00148       }
00149     }
00150   }
00151   
00152   // normalize for 1 GeV pulse height
00153   edm::LogInfo("HcalSim") << "HcalQie: Convoluted Shape ============== "
00154                           << "Normalisation " << norm;
00155   for (i=0; i<nsiz; i++) {
00156     pulse[i] /= norm;
00157 #ifdef DebugLog
00158     LogDebug("HcalSim") << "HcalQie: Pulse[" << std::setw(3) << i << "] " 
00159                         << std::setw(8) << pulse[i];
00160 #endif
00161   }
00162   
00163   return pulse;
00164 }
00165 
00166 std::vector<int> HcalQie::code() {
00167 
00168   unsigned int CodeFADCdata[122] = {
00169       0,     1,      2,      3,      4,      5,      6,      7,      8,      9,
00170      10,    11,     12,     13,     14,     15,     16,     17,     18,     19,
00171      20,    21,     22,     23,     24,     25,     26,     27,     28,     29,
00172      30,    31,                     34,     35,     36,     37,     38,     39,
00173      40,    41,     42,     43,     44,     45,     46,     47,     48,     49,
00174      50,    51,     52,     53,     54,     55,     56,     57,     58,     59,
00175      60,    61,     62,     63,                     66,     67,     68,     69,
00176      70,    71,     72,     73,     74,     75,     76,     77,     78,     79,
00177      80,    81,     82,     83,     84,     85,     86,     87,     88,     89,
00178      90,    91,     92,     93,     94,     95,                     98,     99,
00179     100,   101,    102,    103,    104,    105,    106,    107,    108,    109,
00180     110,   111,    112,    113,    114,    115,    116,    117,    118,    119,
00181     120,   121,    122,    123,    124,    125,    126,    127 };
00182 
00183   std::vector<int> temp(122);
00184   int i;
00185   for (i = 0; i < 122; i++) 
00186     temp[i] = (int)CodeFADCdata[i];
00187 
00188 #ifdef DebugLog
00189   int siz = temp.size();
00190   LogDebug("HcalSim") << "HcalQie: Codes in array of size " << siz;
00191   for (i=0; i<siz; i++)
00192     LogDebug("HcalSim") << "HcalQie: Code[" << std::setw(3) << i << "] " 
00193                         << std::setw(6) << temp[i];
00194 #endif
00195   return temp;
00196 }
00197 
00198 std::vector<double> HcalQie::charge() {
00199 
00200   double ChargeFADCdata[122] =  {
00201    -1.5,  -0.5,    0.5,    1.5,    2.5,    3.5,    4.5,    5.5,    6.5,    7.5,
00202     8.5,   9.5,   10.5,   11.5,   12.5,   13.5,   14.5,   16.5,   18.5,   20.5,
00203    22.5,  24.5,   26.5,   28.5,   31.5,   34.5,   37.5,   40.5,   44.5,   48.5,
00204    52.5,  57.5,                   62.5,   67.5,   72.5,   77.5,   82.5,   87.5,
00205    92.5,  97.5,  102.5,  107.5,  112.5,  117.5,  122.5,  127.5,  132.5,  142.5,
00206   152.5, 162.5,  172.5,  182.5,  192.5,  202.5,  217.5,  232.5,  247.5,  262.5,
00207   282.5, 302.5,  322.5,  347.5,                  372.5,  397.5,  422.5,  447.5,
00208   472.5, 497.5,  522.5,  547.5,  572.5,  597.5,  622.5,  647.5,  672.5,  697.5,
00209   722.5, 772.5,  822.5,  872.5,  922.5,  972.5, 1022.5, 1072.5, 1147.5, 1222.5,
00210  1297.5,1372.5, 1472.5, 1572.5, 1672.5, 1797.5,                 1922.5, 2047.5,
00211  2172.5,2297.5, 2422.5, 2547.5, 2672.5, 2797.5, 2922.5, 3047.5, 3172.5, 3397.5,
00212  3422.5,3547.5, 3672.5, 3922.5, 4172.5, 4422.5, 4672.5, 4922.5, 5172.5, 5422.5,
00213  5797.5,6172.5, 6547.5, 6922.5, 7422.5, 7922.5, 8422.5, 9047.5 };             
00214 
00215   std::vector<double> temp(122);
00216   int i;
00217   for (i = 0; i < 122; i++)
00218     temp[i] = (double)(ChargeFADCdata[i]);
00219 
00220 #ifdef DebugLog
00221   int siz = temp.size();
00222   LogDebug("HcalSim") << "HcalQie: Charges in array of size " << siz;
00223   for (i=0; i<siz; i++)
00224     LogDebug("HcalSim") << "HcalQie: Charge[" << std::setw(3) << i << "] " 
00225                         << std::setw(8) << temp[i];
00226 #endif
00227   return temp;
00228 }
00229 
00230 std::vector<double> HcalQie::weight(int binOfMax, int mode, int npre, 
00231                                     int bucket) {
00232 
00233   std::vector<double> temp(bucket,0);
00234   int i;
00235   for (i=binOfMax-1; i<binOfMax+mode-1; i++)
00236     temp[i] = 1.;
00237   if (npre>0) {
00238     for (i=0; i<npre; i++) {
00239       int j   = binOfMax-2-i;
00240       temp[j] =-(double)mode/(double)npre;
00241     }
00242   }
00243 
00244 #ifdef DebugLog
00245   int siz = temp.size();
00246   LogDebug("HcalSim") << "HcalQie: Weights in array of size " << siz 
00247                       << " and Npre " << npre;
00248   for (i=0; i<siz; i++)
00249     LogDebug("HcalSim") << "HcalQie: [Weight[" << i << "] = " << temp[i];
00250 #endif
00251   return temp;
00252 }
00253 
00254 
00255 double HcalQie::codeToQ(int ic) {
00256 
00257   double tmp=0;
00258   for (unsigned int i=0; i<code_.size(); i++) {
00259     if (ic == code_[i]) {
00260       double delta;
00261       if (i == code_.size()-1) 
00262         delta = charge_[i] - charge_[i-1];
00263       else
00264         delta = charge_[i+1] - charge_[i];
00265       tmp = charge_[i] + 0.5*delta;
00266       break;
00267     }
00268   }
00269 
00270   return tmp;
00271 }
00272 
00273 
00274 int HcalQie::getCode(double charge) {
00275 
00276   int tmp=0;
00277   for (unsigned int i=0; i<charge_.size(); i++) {
00278     if (charge < charge_[i]) {
00279       if (i>0) tmp = code_[i-1];
00280       break;
00281     }
00282   }
00283 
00284   return tmp;
00285 }
00286 
00287 
00288 double HcalQie::getShape(double time) {
00289 
00290   double tmp = 0;
00291   int    k = (int) (time + 0.5);
00292   if (k>=0 && k<((int)(shape_.size())-1))
00293     tmp = 0.5*(shape_[k]+shape_[k+1]);
00294   
00295   return tmp;
00296 }
00297 
00298 
00299 std::vector<int> HcalQie::getCode(int nht, std::vector<CaloHit> hitbuf) {
00300 
00301   const double  bunchSpace=25.;
00302   int nmax = (bmax_ > numOfBuckets ? bmax_ : numOfBuckets);
00303   std::vector<double> work(nmax);
00304 
00305   edm::Service<edm::RandomNumberGenerator> rng;
00306   if ( ! rng.isAvailable()) {
00307     throw cms::Exception("Configuration")
00308       << "HcalQIE requires the RandomNumberGeneratorService\n"
00309       << "which is not present in the configuration file. "
00310       << "You must add the service\n in the configuration file or "
00311       << "remove the modules that require it.";
00312   }
00313   CLHEP::RandGaussQ  randGauss(rng->getEngine(), baseline,sigma);
00314   CLHEP::RandPoissonQ randPoisson(rng->getEngine());
00315 
00316 
00317   // Noise in the channel
00318   for (int i=0; i<numOfBuckets; i++) 
00319     work[i] = randGauss.fire();
00320 
00321 #ifdef DebugLog
00322   LogDebug("HcalSim") << "HcalQie::getCode: Noise with baseline " << baseline 
00323                       << " width " << sigma << " and " << nht << " hits";
00324   for (int i=0; i<numOfBuckets; i++) 
00325     LogDebug("HcalSim") << "HcalQie: Code[" << i << "] = " << work[i];
00326 #endif  
00327   double etot=0, esum=0, photons=0;
00328   if (nht>0) {
00329   
00330     // Sort the hits
00331     std::vector<CaloHit*> hits(nht);
00332     std::vector<CaloHit*>::iterator k1, k2;
00333     int kk;
00334     for (kk = 0; kk < nht; kk++) {
00335       hits[kk] = &hitbuf[kk];
00336     }
00337     sort(hits.begin(),hits.end(),CaloHitMore());
00338     
00339     // Energy deposits
00340     for (kk = 0, k1 = hits.begin(); k1 != hits.end(); kk++, k1++) {
00341       double ehit  = (**k1).e();
00342       double jitter= (**k1).t();
00343       int    jump  = 0;
00344       for (k2 = k1+1; k2 != hits.end() && (jitter-(**k2).t())<1. &&
00345              (jitter-(**k2).t())>-1.; k2++) {
00346         ehit += (**k2).e();
00347         jump++;
00348       }
00349 
00350       double avpe  = ehit/eDepPerPE;
00351       double photo = randPoisson.fire(avpe);
00352       etot   += ehit;
00353       photons+= photo; 
00354 #ifdef DebugLog
00355       LogDebug("HcalSim") << "HcalQie::getCode: Hit " << kk << ":" << kk+jump 
00356                           << " Energy deposit " << ehit << " Time " << jitter
00357                           << " Average and true no of PE " << avpe << " " 
00358                           << photo;
00359 #endif
00360       double bintime = jitter - phase_ - bunchSpace*(binOfMax-bmin_);
00361 #ifdef DebugLog
00362       LogDebug("HcalSim") << "HcalQie::getCode: phase " << phase_  
00363                           << " binTime " << bintime;
00364 #endif
00365       std::vector<double> binsum(nmax,0);
00366       double norm=0, sum=0.;
00367       for (int i=bmin_; i<bmax_; i++) {
00368         bintime += bunchSpace;
00369         for (int j=0; j<(int)(bunchSpace); j++) {
00370           double tim = bintime + j;
00371           double tmp = getShape(tim);
00372           binsum[i] += tmp;
00373         }
00374         sum += binsum[i];
00375       }
00376 
00377       if (sum>0) norm = (photo/(sum*qToPE));
00378 #ifdef DebugLog
00379       LogDebug("HcalSim") << "HcalQie::getCode: PE " << photo << " Sum " << sum
00380                           << " Norm. " << norm;
00381 #endif
00382       for (int i=bmin_; i<bmax_; i++)
00383         work[i] += binsum[i]*norm;
00384 
00385       kk += jump;
00386       k1 += jump;
00387     }
00388   }
00389 
00390   std::vector<int> temp(numOfBuckets,0);
00391   for (int i=0; i<numOfBuckets; i++) {
00392     temp[i] = getCode(work[i]);
00393     esum   += work[i];
00394   }
00395 #ifdef DebugLog
00396   LogDebug("HcalSim") << "HcalQie::getCode: Input " << etot << " GeV; Photons "
00397                       << photons << ";  Output " << esum << " fc";
00398 #endif
00399   return temp;
00400 }
00401 
00402 
00403 double HcalQie::getEnergy(std::vector<int> code) {
00404 
00405   std::vector<double> work(numOfBuckets);
00406   double sum=0;
00407   for (int i=0; i<numOfBuckets; i++) {
00408     work[i] = codeToQ (code[i]);
00409     sum += work[i]*weight_[i];
00410 #ifdef DebugLog
00411     LogDebug("HcalSim") << "HcalQie::getEnergy: " << i << " code " << code[i] 
00412                         << " PE " << work[i];
00413 #endif
00414   }
00415 
00416   double tmp;
00417   if (preSamples == 0) {
00418     tmp = (sum - signalBuckets*baseline) * rescale_ * qToPE * eDepPerPE;
00419   } else {
00420     tmp = sum * rescale_ * qToPE;
00421   }
00422 #ifdef DebugLog
00423   LogDebug("HcalSim") << "HcalQie::getEnergy: PE " << sum*qToPE << " Energy " 
00424                       << tmp << " GeV";
00425 #endif
00426   return tmp;
00427 }