CMS 3D CMS Logo

HcalSiPM.cc
Go to the documentation of this file.
3 
4 #include "CLHEP/Random/RandGaussQ.h"
5 #include "CLHEP/Random/RandPoissonQ.h"
6 #include "CLHEP/Random/RandFlat.h"
7 #include "TMath.h"
8 #include <cmath>
9 #include <cassert>
10 #include <utility>
11 
12 using std::vector;
13 //345678911234567892123456789312345678941234567895123456789612345678971234567898
14 HcalSiPM::HcalSiPM(int nCells, double tau) :
15  theCellCount(nCells), theSiPM(nCells,1.),
16  theCrossTalk(0.), theTempDep(0.), theLastHitTime(-1.), nonlin(0)
17 {
18  setTau(tau);
19  assert(theCellCount>0);
20  resetSiPM();
21 }
22 
24 }
25 
26 //================================================================================
27 //implementation of Borel-Tanner distribution
28 double HcalSiPM::Borel(unsigned int n, double lambda, unsigned int k){
29  if(n<k) return 0;
30  double dn = double(n);
31  double dk = double(k);
32  double dnk = dn-dk;
33  double ldn = lambda * dn;
34  double logb = -ldn + dnk*log(ldn) - TMath::LnGamma(dnk+1);
35  double b=0;
36  if (logb >= -20) { // protect against underflow
37  b=(dk/dn);
38  if ((n-k)<100)
39  b *= (exp(-ldn)*pow(ldn,dnk))/TMath::Factorial(n-k);
40  else
41  b *= exp( logb );
42  }
43  return b;
44 }
45 
46 const HcalSiPM::cdfpair& HcalSiPM::BorelCDF(unsigned int k){
47  // EPSILON determines the min and max # of xtalk cells that can be
48  // simulated.
49  static const double EPSILON = 1e-6;
50  typename cdfmap::const_iterator it;
51  it = borelcdfs.find(k);
52  if (it == borelcdfs.end()) {
53  vector<double> cdf;
54 
55  // Find the first n=k+i value for which cdf[i] > EPSILON
56  unsigned int i;
57  double b=0., sumb=0.;
58  for (i=0; ; i++) {
59  b = Borel(k+i,theCrossTalk,k);
60  sumb += b;
61  if (sumb >= EPSILON) break;
62  }
63 
64  cdf.push_back(sumb);
65  unsigned int borelstartn = i;
66 
67  // calculate cdf[i]
68  for(++i; ; ++i){
69  b = Borel(k+i,theCrossTalk,k);
70  sumb += b;
71  cdf.push_back(sumb);
72  if (1-sumb < EPSILON) break;
73  }
74 
75  it = (borelcdfs.emplace(k,make_pair(borelstartn, cdf))).first;
76  }
77 
78  return it->second;
79 }
80 
81 unsigned int HcalSiPM::addCrossTalkCells(CLHEP::HepRandomEngine* engine,
82  unsigned int in_pes) {
83  const cdfpair& cdf = BorelCDF(in_pes);
84 
85  double U = CLHEP::RandFlat::shoot(engine);
86  std::vector<double>::const_iterator up;
87  up= std::lower_bound (cdf.second.cbegin(), cdf.second.cend(), U);
88 
89  LogDebug("HcalSiPM") << "cdf size = " << cdf.second.size()
90  << ", U = " << U
91  << ", in_pes = " << in_pes
92  << ", 2ndary_pes = " << (up-cdf.second.cbegin()+cdf.first);
93 
94  // returns the number of secondary pes produced
95  return (up - cdf.second.cbegin() + cdf.first);
96 }
97 
98 //================================================================================
99 
100 double HcalSiPM::hitCells(CLHEP::HepRandomEngine* engine, unsigned int pes, double tempDiff,
101  double photonTime) {
102  // response to light impulse with pes input photons. The return is the number
103  // of micro-pixels hit. If a fraction other than 0. is supplied then the
104  // micro-pixel doesn't fully discharge. The tempDiff is the temperature
105  // difference from nominal and is used to modify the relative strength of a
106  // hit pixel. Pixels which are fractionally charged return a fractional
107  // number of hit pixels.
108 
109  if ((theCrossTalk > 0.) && (theCrossTalk < 1.))
110  pes += addCrossTalkCells(engine, pes);
111 
112  // Account for saturation - disabled in lieu of recovery model below
113  //pes = nonlin->getPixelsFired(pes);
114 
115  //disable saturation/recovery model for bad tau values
116  if(theTau<=0) return pes;
117 
118  unsigned int pixel;
119  double sum(0.), hit(0.);
120  for (unsigned int pe(0); pe < pes; ++pe) {
121  pixel = CLHEP::RandFlat::shootInt(engine, theCellCount);
122  hit = (theSiPM[pixel] < 0.) ? 1.0 :
123  (cellCharge(photonTime - theSiPM[pixel]));
124  sum += hit*(1 + (tempDiff*theTempDep));
125  theSiPM[pixel] = photonTime;
126  }
127 
128  theLastHitTime = photonTime;
129 
130  return sum;
131 }
132 
133 double HcalSiPM::totalCharge(double time) const {
134  // sum of the micro-pixels. NP is a fully charged device.
135  // 0 is a fullly depleted device.
136  double tot(0.), hit(0.);
137  for(unsigned int i=0; i<theCellCount; ++i) {
138  hit = (theSiPM[i] < 0.) ? 1. : cellCharge(time - theSiPM[i]);
139  tot += hit;
140  }
141  return tot;
142 }
143 
144 void HcalSiPM::setNCells(int nCells) {
145  assert(nCells>0);
146  theCellCount = nCells;
147  theSiPM.resize(nCells);
148  resetSiPM();
149 }
150 
151 void HcalSiPM::setTau(double tau) {
152  theTau = tau;
153  if(theTau > 0) theTauInv = 1./theTau;
154  else theTauInv = 0;
155 }
156 
158  // set the cross-talk probability
159 
160  double oldCrossTalk = theCrossTalk;
161 
162  if((xTalk < 0) || (xTalk >= 1)) {
163  theCrossTalk = 0.;
164  } else {
166  }
167 
168  // Recalculate the crosstalk CDFs
169  if (theCrossTalk != oldCrossTalk) {
170  borelcdfs.clear();
171  if (theCrossTalk > 0)
172  for (int k=1; k<=100; k++)
173  BorelCDF(k);
174  }
175 }
176 
178  // set the temperature dependence
179  theTempDep = dTemp;
180 }
181 
182 double HcalSiPM::cellCharge(double deltaTime) const {
183  if (deltaTime <= 0.) return 0.;
184  if (deltaTime*theTauInv > 10.) return 1.;
185  double result(1. - std::exp(-deltaTime*theTauInv));
186  return (result > 0.99) ? 1.0 : result;
187 }
188 
189 void HcalSiPM::setSaturationPars(const std::vector<float>& pars)
190 {
191  if (nonlin)
192  delete nonlin;
193 
194  nonlin = new HcalSiPMnonlinearity(pars);
195 }
#define LogDebug(id)
Definition: BitonicSort.h:8
int i
Definition: DBlmapReader.cc:9
double theTempDep
Definition: HcalSiPM.h:66
virtual ~HcalSiPM()
Definition: HcalSiPM.cc:23
double cellCharge(double deltaTime) const
Definition: HcalSiPM.cc:182
void setSaturationPars(const std::vector< float > &pars)
Definition: HcalSiPM.cc:189
virtual double totalCharge() const
Definition: HcalSiPM.h:33
double theTauInv
Definition: HcalSiPM.h:64
void resetSiPM()
Definition: HcalSiPM.h:28
double theCrossTalk
Definition: HcalSiPM.h:65
std::vector< double > theSiPM
Definition: HcalSiPM.h:62
const cdfpair & BorelCDF(unsigned int k)
Definition: HcalSiPM.cc:46
double Borel(unsigned int n, double lambda, unsigned int k)
Definition: HcalSiPM.cc:28
virtual double hitCells(CLHEP::HepRandomEngine *, unsigned int pes, double tempDiff=0., double photonTime=0.)
Definition: HcalSiPM.cc:100
void setNCells(int nCells)
Definition: HcalSiPM.cc:144
void setTau(double tau)
Definition: HcalSiPM.cc:151
double theLastHitTime
Definition: HcalSiPM.h:67
void setCrossTalk(double xtalk)
Definition: HcalSiPM.cc:157
int k[5][pyjets_maxn]
cdfmap borelcdfs
Definition: HcalSiPM.h:71
const float EPSILON
Definition: AnglesUtil.h:23
unsigned int addCrossTalkCells(CLHEP::HepRandomEngine *engine, unsigned int in_pes)
Definition: HcalSiPM.cc:81
HcalSiPMnonlinearity * nonlin
Definition: HcalSiPM.h:69
double b
Definition: hdecay.h:120
double theTau
Definition: HcalSiPM.h:63
unsigned int theCellCount
Definition: HcalSiPM.h:61
HcalSiPM(int nCells=1, double tau=15.)
Definition: HcalSiPM.cc:14
void setTemperatureDependence(double tempDep)
Definition: HcalSiPM.cc:177
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
std::pair< unsigned int, std::vector< double > > cdfpair
Definition: HcalSiPM.h:49