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