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