Skip to content

Commit fb4e41e

Browse files
authored
Merge pull request cms-sw#40634 from VinInn/SpeedupHCalPreMix4
Spedup HCAL Digitization
2 parents 01c7544 + e43317c commit fb4e41e

File tree

7 files changed

+138
-94
lines changed

7 files changed

+138
-94
lines changed

CondFormats/HcalObjects/src/HcalSiPMCharacteristics.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ int HcalSiPMCharacteristics::getPixels(int type) const {
7777
std::vector<float> HcalSiPMCharacteristics::getNonLinearities(int type) const {
7878
const HcalSiPMCharacteristics::PrecisionItem* item = findByType(type);
7979
std::vector<float> pars;
80+
pars.reserve(3);
8081
if (item) {
8182
pars.push_back(item->parLin1_);
8283
pars.push_back(item->parLin2_);

SimCalorimetry/HcalSimAlgos/interface/HcalSiPM.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ namespace CLHEP {
1919
class HepRandomEngine;
2020
}
2121

22-
class HcalSiPM {
22+
class HcalSiPM final {
2323
public:
2424
HcalSiPM(int nCells = 1, double tau = 15.);
2525

26-
virtual ~HcalSiPM();
26+
~HcalSiPM();
2727

28-
void resetSiPM() { std::fill(theSiPM.begin(), theSiPM.end(), -999.); }
29-
virtual double hitCells(CLHEP::HepRandomEngine*, unsigned int pes, double tempDiff = 0., double photonTime = 0.);
28+
void resetSiPM() { std::fill(theSiPM.begin(), theSiPM.end(), -999.f); }
29+
double hitCells(CLHEP::HepRandomEngine*, unsigned int pes, double tempDiff = 0., double photonTime = 0.);
3030

31-
virtual double totalCharge() const { return totalCharge(theLastHitTime); }
32-
virtual double totalCharge(double time) const;
31+
double totalCharge() const { return totalCharge(theLastHitTime); }
32+
double totalCharge(double time) const;
3333

3434
int getNCells() const { return theCellCount; }
3535
double getTau() const { return theTau; }
@@ -52,11 +52,10 @@ class HcalSiPM {
5252
unsigned int addCrossTalkCells(CLHEP::HepRandomEngine* engine, unsigned int in_pes);
5353

5454
//numerical random generation from Borel-Tanner distribution
55-
double Borel(unsigned int n, double lambda, unsigned int k);
5655
const cdfpair& BorelCDF(unsigned int k);
5756

5857
unsigned int theCellCount;
59-
std::vector<double> theSiPM;
58+
std::vector<float> theSiPM;
6059
double theTau;
6160
double theTauInv;
6261
double theCrossTalk;

SimCalorimetry/HcalSimAlgos/interface/HcalSiPMHitResponse.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class PCaloHitCompareTimes {
1919
bool operator()(const PCaloHit* a, const PCaloHit* b) const { return a->time() < b->time(); }
2020
};
2121

22-
class HcalSiPMHitResponse : public CaloHitResponse {
22+
class HcalSiPMHitResponse final : public CaloHitResponse {
2323
public:
2424
HcalSiPMHitResponse(const CaloVSimParameterMap* parameterMap,
2525
const CaloShapes* shapes,

SimCalorimetry/HcalSimAlgos/interface/HcalSiPMShape.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,24 @@
22
#ifndef HcalSimAlgos_HcalSiPMShape_h
33
#define HcalSimAlgos_HcalSiPMShape_h
44

5+
#include "CalibCalorimetry/HcalAlgos/interface/HcalPulseShapes.h"
56
#include "SimCalorimetry/CaloSimAlgos/interface/CaloVShape.h"
67
#include <vector>
78

8-
class HcalSiPMShape : public CaloVShape {
9+
class HcalSiPMShape final : public CaloVShape {
910
public:
1011
HcalSiPMShape(unsigned int signalShape = 206);
1112
HcalSiPMShape(const HcalSiPMShape& other);
1213

1314
~HcalSiPMShape() override {}
1415

15-
double operator()(double time) const override;
16+
int nBins() const { return nBins_; }
17+
double operator[](int i) const { return nt_[i]; }
18+
19+
double operator()(double time) const override {
20+
int jtime(time * HcalPulseShapes::invDeltaTSiPM_ + 0.5);
21+
return (jtime >= 0 && jtime < nBins_) ? nt_[jtime] : 0;
22+
}
1623

1724
double timeToRise() const override { return 0.0; }
1825

SimCalorimetry/HcalSimAlgos/src/HcalSiPM.cc

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,69 +12,104 @@
1212
using std::vector;
1313
//345678911234567892123456789312345678941234567895123456789612345678971234567898
1414
HcalSiPM::HcalSiPM(int nCells, double tau)
15-
: theCellCount(nCells), theSiPM(nCells, 1.), theCrossTalk(0.), theTempDep(0.), theLastHitTime(-1.), nonlin(nullptr) {
15+
: theCellCount(nCells),
16+
theSiPM(nCells, -999.f),
17+
theCrossTalk(0.),
18+
theTempDep(0.),
19+
theLastHitTime(-1.),
20+
nonlin(nullptr) {
1621
setTau(tau);
1722
assert(theCellCount > 0);
18-
resetSiPM();
1923
}
2024

2125
HcalSiPM::~HcalSiPM() {
2226
if (nonlin)
2327
delete nonlin;
2428
}
2529

26-
//================================================================================
27-
//implementation of Borel-Tanner distribution
28-
double HcalSiPM::Borel(unsigned int n, double lambda, unsigned int k) {
29-
if (n < k)
30-
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);
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;
4376
}
44-
return b;
45-
}
77+
78+
} // namespace
4679

4780
const HcalSiPM::cdfpair& HcalSiPM::BorelCDF(unsigned int k) {
4881
// EPSILON determines the min and max # of xtalk cells that can be
4982
// simulated.
50-
static const double EPSILON = 1e-6;
51-
typename cdfmap::const_iterator it;
52-
it = borelcdfs.find(k);
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);
5386
if (it == borelcdfs.end()) {
5487
vector<double> cdf;
88+
cdf.reserve(64);
5589

5690
// Find the first n=k+i value for which cdf[i] > EPSILON
5791
unsigned int i;
58-
double b = 0., sumb = 0.;
59-
for (i = 0;; i++) {
60-
b = Borel(k + i, theCrossTalk, k);
61-
sumb += b;
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);
6298
if (sumb >= EPSILON)
6399
break;
64100
}
65101

66102
cdf.push_back(sumb);
67103
unsigned int borelstartn = i;
68104

69-
// calculate cdf[i]
70-
for (++i;; ++i) {
71-
b = Borel(k + i, theCrossTalk, k);
72-
sumb += b;
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);
73109
cdf.push_back(sumb);
74-
if (1 - sumb < EPSILON)
110+
if (1. - sumb < EPSILON)
75111
break;
76112
}
77-
78113
it = (borelcdfs.emplace(k, make_pair(borelstartn, cdf))).first;
79114
}
80115

@@ -141,7 +176,6 @@ double HcalSiPM::totalCharge(double time) const {
141176
}
142177

143178
void HcalSiPM::setNCells(int nCells) {
144-
assert(nCells > 0);
145179
theCellCount = nCells;
146180
theSiPM.resize(nCells);
147181
resetSiPM();

SimCalorimetry/HcalSimAlgos/src/HcalSiPMHitResponse.cc

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -205,59 +205,69 @@ CaloSamples HcalSiPMHitResponse::makeSiPMSignal(DetId const& id,
205205
unsigned int pe(0);
206206
double hitPixels(0.), elapsedTime(0.);
207207

208-
auto& sipmPulseShape(shapeMap[pars.signalShape(id)]);
208+
auto const& sipmPulseShape(shapeMap[pars.signalShape(id)]);
209209

210-
std::list<std::pair<double, double> > pulses;
211-
std::list<std::pair<double, double> >::iterator pulse;
212-
double timeDiff, pulseBit;
213210
LogDebug("HcalSiPMHitResponse") << "makeSiPMSignal for " << HcalDetId(id);
214211

215-
for (unsigned int tbin(0); tbin < photonTimeBins.size(); ++tbin) {
212+
const int nptb = photonTimeBins.size();
213+
double sum[nptb];
214+
for (auto i = 0; i < nptb; ++i)
215+
sum[i] = 0;
216+
for (int tbin(0); tbin < nptb; ++tbin) {
216217
pe = photonTimeBins[tbin];
218+
if (pe <= 0)
219+
continue;
217220
preciseBin = tbin;
218221
sampleBin = preciseBin / nbins;
219-
if (pe > 0) {
220-
//skip saturation/recovery and pulse smearing for premix stage 1
221-
if (PreMixDigis and HighFidelityPreMix) {
222-
signal[sampleBin] += pe;
223-
signal.preciseAtMod(preciseBin) += pe;
224-
elapsedTime += dt;
225-
continue;
226-
}
227-
228-
hitPixels = theSiPM.hitCells(engine, pe, 0., elapsedTime);
229-
LogDebug("HcalSiPMHitResponse") << " elapsedTime: " << elapsedTime << " sampleBin: " << sampleBin
230-
<< " preciseBin: " << preciseBin << " pe: " << pe << " hitPixels: " << hitPixels;
231-
if (pars.doSiPMSmearing()) {
232-
pulses.push_back(std::pair<double, double>(elapsedTime, hitPixels));
233-
} else {
234-
signal[sampleBin] += hitPixels;
235-
signal.preciseAtMod(preciseBin) += 0.6 * hitPixels;
236-
if (preciseBin > 0)
237-
signal.preciseAtMod(preciseBin - 1) += 0.2 * hitPixels;
238-
if (preciseBin < signal.preciseSize() - 1)
239-
signal.preciseAtMod(preciseBin + 1) += 0.2 * hitPixels;
240-
}
222+
//skip saturation/recovery and pulse smearing for premix stage 1
223+
if (PreMixDigis and HighFidelityPreMix) {
224+
signal[sampleBin] += pe;
225+
signal.preciseAtMod(preciseBin) += pe;
226+
elapsedTime += dt;
227+
continue;
241228
}
242229

243-
if (pars.doSiPMSmearing()) {
244-
pulse = pulses.begin();
245-
while (pulse != pulses.end()) {
246-
timeDiff = elapsedTime - pulse->first;
247-
pulseBit = sipmPulseShape(timeDiff) * pulse->second;
248-
LogDebug("HcalSiPMHitResponse") << " pulse t: " << pulse->first << " pulse A: " << pulse->second
249-
<< " timeDiff: " << timeDiff << " pulseBit: " << pulseBit;
250-
signal[sampleBin] += pulseBit;
251-
signal.preciseAtMod(preciseBin) += pulseBit;
252-
253-
if (timeDiff > 1 && sipmPulseShape(timeDiff) < 1e-7)
254-
pulse = pulses.erase(pulse);
255-
else
256-
++pulse;
230+
hitPixels = theSiPM.hitCells(engine, pe, 0., elapsedTime);
231+
LogDebug("HcalSiPMHitResponse") << " elapsedTime: " << elapsedTime << " sampleBin: " << sampleBin
232+
<< " preciseBin: " << preciseBin << " pe: " << pe << " hitPixels: " << hitPixels;
233+
if (!pars.doSiPMSmearing()) {
234+
signal[sampleBin] += hitPixels;
235+
signal.preciseAtMod(preciseBin) += 0.6 * hitPixels;
236+
if (preciseBin > 0)
237+
signal.preciseAtMod(preciseBin - 1) += 0.2 * hitPixels;
238+
if (preciseBin < signal.preciseSize() - 1)
239+
signal.preciseAtMod(preciseBin + 1) += 0.2 * hitPixels;
240+
} else {
241+
// add "my" smearing to future bins...
242+
// this loop can vectorize....
243+
for (auto i = tbin; i < nptb; ++i) {
244+
auto itdiff = i - tbin;
245+
if (itdiff == sipmPulseShape.nBins())
246+
break;
247+
auto shape = sipmPulseShape[itdiff];
248+
auto pulseBit = shape * hitPixels;
249+
sum[i] += pulseBit;
250+
if (shape < 1.e-7 && itdiff > int(HcalPulseShapes::invDeltaTSiPM_))
251+
break;
257252
}
258253
}
259254
elapsedTime += dt;
260255
}
256+
if (pars.doSiPMSmearing())
257+
for (auto i = 0; i < nptb; ++i) {
258+
auto iSampleBin = i / nbins;
259+
signal[iSampleBin] += sum[i];
260+
signal.preciseAtMod(i) += sum[i];
261+
}
262+
263+
#ifdef EDM_ML_DEBUG
264+
LogDebug("HcalSiPMHitResponse") << nbins << ' ' << nptb << ' ' << HcalDetId(id);
265+
for (auto i = 0; i < nptb; ++i) {
266+
auto iSampleBin = (nbins > 1) ? i / nbins : i;
267+
LogDebug("HcalSiPMHitResponse") << i << ' ' << iSampleBin << ' ' << signal[iSampleBin] << ' '
268+
<< signal.preciseAtMod(i);
269+
}
270+
#endif
261271

262272
return signal;
263273
}

SimCalorimetry/HcalSimAlgos/src/HcalSiPMShape.cc

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,6 @@ HcalSiPMShape::HcalSiPMShape(unsigned int signalShape)
1010

1111
HcalSiPMShape::HcalSiPMShape(const HcalSiPMShape& other) : CaloVShape(other), nBins_(other.nBins_), nt_(other.nt_) {}
1212

13-
double HcalSiPMShape::operator()(double time) const {
14-
int jtime(time * HcalPulseShapes::invDeltaTSiPM_ + 0.5);
15-
if (jtime >= 0 && jtime < nBins_)
16-
return nt_[jtime];
17-
return 0.;
18-
}
19-
2013
void HcalSiPMShape::computeShape(unsigned int signalShape) {
2114
//grab correct function pointer based on shape
2215
double (*analyticPulseShape)(double);

0 commit comments

Comments
 (0)