CMS 3D CMS Logo

HcalSiPMHitResponse.cc
Go to the documentation of this file.
13 
14 #include "CLHEP/Random/RandPoissonQ.h"
15 
16 #include <cmath>
17 #include <list>
18 
20  const CaloShapes* shapes,
21  bool PreMix1,
22  bool HighFidelity)
23  : CaloHitResponse(parameterMap, shapes),
24  theSiPM(),
25  PreMixDigis(PreMix1),
26  HighFidelityPreMix(HighFidelity),
27  nbins((PreMixDigis and HighFidelityPreMix) ? 1 : BUNCHSPACE * HcalPulseShapes::invDeltaTSiPM_),
28  dt(HcalPulseShapes::deltaTSiPM_),
29  invdt(HcalPulseShapes::invDeltaTSiPM_) {
30  //fill shape map
35 }
36 
38 
40 
43  int readoutFrameSize = parameters.readoutFrameSize();
45  //preserve fidelity of time info
47  }
48  return readoutFrameSize;
49 }
50 
51 void HcalSiPMHitResponse::finalizeHits(CLHEP::HepRandomEngine* engine) {
52  //do not add PE noise for initial premix
53  if (!PreMixDigis)
54  addPEnoise(engine);
55 
56  photonTimeMap::iterator channelPhotons;
57  for (channelPhotons = precisionTimedPhotons.begin(); channelPhotons != precisionTimedPhotons.end();
58  ++channelPhotons) {
59  CaloSamples signal(makeSiPMSignal(channelPhotons->first, channelPhotons->second, engine));
60  bool keep(keepBlank());
61  if (!keep) {
62  const unsigned int size(signal.size());
63  if (0 != size) {
64  for (unsigned int i(0); i != size; ++i) {
65  keep = keep || signal[i] > 1.e-7;
66  }
67  }
68  }
69 
70  LogDebug("HcalSiPMHitResponse") << HcalDetId(signal.id()) << ' ' << signal;
71 
72  //if we don't want to keep precise info at the end
73  if (!HighFidelityPreMix) {
74  signal.setPreciseSize(0);
75  }
76 
77  if (keep)
78  CaloHitResponse::add(signal);
79  }
80 }
81 
82 //used for premixing - premixed CaloSamples have fine time binning
84  if (!HighFidelityPreMix) {
85  CaloHitResponse::add(signal);
86  return;
87  }
88  DetId id(signal.id());
89 #ifdef EDM_ML_DEBUG
90  int photonTimeHistSize = nbins * getReadoutFrameSize(id);
91  assert(photonTimeHistSize == signal.size());
92 #endif
93  auto photI = precisionTimedPhotons.find(id);
94  if (photI == precisionTimedPhotons.end()) {
95  photI = precisionTimedPhotons.emplace(id, photonTimeHist(signal.size(), 0)).first;
96  }
97  auto& phot = photI->second;
98  for (int i = 0; i < signal.size(); ++i) {
99  unsigned int photons(signal[i] + 0.5);
100  phot[i] += photons;
101  }
102 }
103 
104 void HcalSiPMHitResponse::add(const PCaloHit& hit, CLHEP::HepRandomEngine* engine) {
105  if (!edm::isNotFinite(hit.time()) && ((theHitFilter == nullptr) || (theHitFilter->accepts(hit)))) {
106  HcalDetId id(hit.id());
107  const HcalSimParameters& pars = dynamic_cast<const HcalSimParameters&>(theParameterMap->simParameters(id));
108  //divide out mean of crosstalk distribution 1/(1-lambda) = multiply by (1-lambda)
109  double signal(analogSignalAmplitude(id, hit.energy(), pars, engine) * (1 - pars.sipmCrossTalk(id)));
110  unsigned int photons(signal + 0.5);
111  double tof(timeOfFlight(id));
112  double time(hit.time());
113  if (ignoreTime)
114  time = tof;
115 
116  if (photons > 0)
117  if (precisionTimedPhotons.find(id) == precisionTimedPhotons.end()) {
118  precisionTimedPhotons.insert(
119  std::pair<DetId, photonTimeHist>(id, photonTimeHist(nbins * getReadoutFrameSize(id), 0)));
120  }
121 
122  LogDebug("HcalSiPMHitResponse") << id;
123  LogDebug("HcalSiPMHitResponse") << " fCtoGeV: " << pars.fCtoGeV(id)
124  << " samplingFactor: " << pars.samplingFactor(id)
125  << " photoelectronsToAnalog: " << pars.photoelectronsToAnalog(id)
126  << " simHitToPhotoelectrons: " << pars.simHitToPhotoelectrons(id);
127  LogDebug("HcalSiPMHitResponse") << " energy: " << hit.energy() << " photons: " << photons << " time: " << time;
128  LogDebug("HcalSiPMHitResponse") << " timePhase: " << pars.timePhase() << " tof: " << tof
129  << " binOfMaximum: " << pars.binOfMaximum() << " phaseShift: " << thePhaseShift_;
130  double tzero(0.0 + pars.timePhase() - (time - tof) - BUNCHSPACE * (pars.binOfMaximum() - thePhaseShift_));
131  LogDebug("HcalSiPMHitResponse") << " tzero: " << tzero;
132  double tzero_bin(-tzero * invdt);
133  LogDebug("HcalSiPMHitResponse") << " corrected tzero: " << tzero_bin << '\n';
134  double t_pe(0.);
135  int t_bin(0);
136  unsigned signalShape = pars.signalShape(id);
137  for (unsigned int pe(0); pe < photons; ++pe) {
138  t_pe = HcalPulseShapes::generatePhotonTime(engine, signalShape);
139  t_bin = int(t_pe * invdt + tzero_bin + 0.5);
140  LogDebug("HcalSiPMHitResponse") << "t_pe: " << t_pe << " t_pe + tzero: " << (t_pe + tzero_bin * dt)
141  << " t_bin: " << t_bin << '\n';
142  if ((t_bin >= 0) && (static_cast<unsigned int>(t_bin) < precisionTimedPhotons[id].size()))
143  precisionTimedPhotons[id][t_bin] += 1;
144  }
145  }
146 }
147 
148 void HcalSiPMHitResponse::addPEnoise(CLHEP::HepRandomEngine* engine) {
149  // Add SiPM dark current noise to all cells
150  for (std::vector<DetId>::const_iterator idItr = theDetIds->begin(); idItr != theDetIds->end(); ++idItr) {
151  HcalDetId id(*idItr);
152  const HcalSimParameters& pars = static_cast<const HcalSimParameters&>(theParameterMap->simParameters(id));
153 
154  // uA * ns / (fC/pe) = pe!
155  double dc_pe_avg = pars.sipmDarkCurrentuA(id) * dt / pars.photoelectronsToAnalog(id);
156 
157  if (dc_pe_avg <= 0.)
158  continue;
159 
160  int nPreciseBins = nbins * getReadoutFrameSize(id);
161 
162  unsigned int sumnoisePE(0);
163  for (int tprecise(0); tprecise < nPreciseBins; ++tprecise) {
164  int noisepe = CLHEP::RandPoissonQ::shoot(engine, dc_pe_avg); // add dark current noise
165 
166  if (noisepe > 0) {
167  if (precisionTimedPhotons.find(id) == precisionTimedPhotons.end()) {
168  photonTimeHist photons(nPreciseBins, 0);
169  photons[tprecise] = noisepe;
170  precisionTimedPhotons.insert(std::pair<DetId, photonTimeHist>(id, photons));
171  } else {
172  precisionTimedPhotons[id][tprecise] += noisepe;
173  }
174 
175  sumnoisePE += noisepe;
176  }
177 
178  } // precise time loop
179 
180  LogDebug("HcalSiPMHitResponse") << id;
181  LogDebug("HcalSiPMHitResponse") << " total noise (PEs): " << sumnoisePE;
182 
183  } // detId loop
184 } // HcalSiPMHitResponse::addPEnoise()
185 
189  int preciseSize(readoutFrameSize * nbins);
190  CaloSamples result(detId, readoutFrameSize, preciseSize);
191  result.setPresamples(parameters.binOfMaximum() - 1);
192  result.setPrecise(result.presamples() * nbins, dt);
193  return result;
194 }
195 
197  photonTimeHist const& photonTimeBins,
198  CLHEP::HepRandomEngine* engine) {
199  const HcalSimParameters& pars = static_cast<const HcalSimParameters&>(theParameterMap->simParameters(id));
200  theSiPM.setNCells(pars.pixels(id));
201  theSiPM.setTau(pars.sipmTau());
204 
205  //use to make signal
206  CaloSamples signal(makeBlankSignal(id));
207  int sampleBin(0), preciseBin(0);
208  signal.resetPrecise();
209  unsigned int pe(0);
210  double hitPixels(0.), elapsedTime(0.);
211 
212  auto const& sipmPulseShape(shapeMap[pars.signalShape(id)]);
213 
214  LogDebug("HcalSiPMHitResponse") << "makeSiPMSignal for " << HcalDetId(id);
215 
216  const int nptb = photonTimeBins.size();
217  double sum[nptb];
218  for (auto i = 0; i < nptb; ++i)
219  sum[i] = 0;
220  for (int tbin(0); tbin < nptb; ++tbin) {
221  pe = photonTimeBins[tbin];
222  if (pe <= 0)
223  continue;
224  preciseBin = tbin;
225  sampleBin = preciseBin / nbins;
226  //skip saturation/recovery and pulse smearing for premix stage 1
228  signal[sampleBin] += pe;
229  signal.preciseAtMod(preciseBin) += pe;
230  elapsedTime += dt;
231  continue;
232  }
233 
234  hitPixels = theSiPM.hitCells(engine, pe, 0., elapsedTime);
235  LogDebug("HcalSiPMHitResponse") << " elapsedTime: " << elapsedTime << " sampleBin: " << sampleBin
236  << " preciseBin: " << preciseBin << " pe: " << pe << " hitPixels: " << hitPixels;
237  if (!pars.doSiPMSmearing()) {
238  signal[sampleBin] += hitPixels;
239  signal.preciseAtMod(preciseBin) += 0.6 * hitPixels;
240  if (preciseBin > 0)
241  signal.preciseAtMod(preciseBin - 1) += 0.2 * hitPixels;
242  if (preciseBin < signal.preciseSize() - 1)
243  signal.preciseAtMod(preciseBin + 1) += 0.2 * hitPixels;
244  } else {
245  // add "my" smearing to future bins...
246  // this loop can vectorize....
247  for (auto i = tbin; i < nptb; ++i) {
248  auto itdiff = i - tbin;
249  if (itdiff == sipmPulseShape.nBins())
250  break;
251  auto shape = sipmPulseShape[itdiff];
252  auto pulseBit = shape * hitPixels;
253  sum[i] += pulseBit;
254  if (shape < 1.e-7 && itdiff > int(HcalPulseShapes::invDeltaTSiPM_))
255  break;
256  }
257  }
258  elapsedTime += dt;
259  }
260  if (pars.doSiPMSmearing())
261  for (auto i = 0; i < nptb; ++i) {
262  auto iSampleBin = i / nbins;
263  signal[iSampleBin] += sum[i];
264  signal.preciseAtMod(i) += sum[i];
265  }
266 
267 #ifdef EDM_ML_DEBUG
268  LogDebug("HcalSiPMHitResponse") << nbins << ' ' << nptb << ' ' << HcalDetId(id);
269  for (auto i = 0; i < nptb; ++i) {
270  auto iSampleBin = (nbins > 1) ? i / nbins : i;
271  LogDebug("HcalSiPMHitResponse") << i << ' ' << iSampleBin << ' ' << signal[iSampleBin] << ' '
272  << signal.preciseAtMod(i);
273  }
274 #endif
275 
276  return signal;
277 }
278 
279 void HcalSiPMHitResponse::setDetIds(const std::vector<DetId>& detIds) { theDetIds = &detIds; }
size
Write out results.
float dt
Definition: AMPTWrapper.h:136
int size() const
get the size
Definition: CaloSamples.h:24
const std::vector< DetId > * theDetIds
void finalizeHits(CLHEP::HepRandomEngine *) override
Finalize hits.
void setSaturationPars(const std::vector< float > &pars)
Definition: HcalSiPM.cc:226
constexpr bool isNotFinite(T x)
Definition: isFinite.h:9
virtual int getReadoutFrameSize(const DetId &id) const
int pixels(const DetId &detId) const
void resetPrecise()
Definition: CaloSamples.cc:31
assert(be >=bs)
Main class for Parameters in different subdetectors.
double sipmCrossTalk(const DetId &detId) const
virtual void addPEnoise(CLHEP::HepRandomEngine *engine)
double analogSignalAmplitude(const DetId &id, float energy, const CaloSimParameters &parameters, CLHEP::HepRandomEngine *) const
virtual CaloSamples makeBlankSignal(const DetId &detId) const
bool doSiPMSmearing() const
Creates electronics signals from hits.
DetId id() const
get the (generic) id
Definition: CaloSamples.h:21
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
virtual bool keepBlank() const
double sipmDarkCurrentuA(const DetId &detId) const
int preciseSize() const
get the size
Definition: CaloSamples.h:70
virtual const CaloSimParameters & simParameters(const DetId &id) const =0
void add(const PCaloHit &hit, CLHEP::HepRandomEngine *) override
process a single SimHit
void setCrossTalk(double xtalk)
Definition: HcalSiPM.cc:192
virtual void setDetIds(const std::vector< DetId > &detIds)
virtual bool accepts(const PCaloHit &hit) const =0
unsigned int signalShape(const DetId &detId) const
unsigned int id
static constexpr float invDeltaTSiPM_
Definition: DetId.h:17
std::vector< unsigned int > photonTimeHist
const CaloVSimParameterMap * theParameterMap
static double generatePhotonTime(CLHEP::HepRandomEngine *engine, unsigned int signalShape)
void initializeHits() override
Initialize hits.
virtual CaloSamples makeSiPMSignal(DetId const &id, photonTimeHist const &photons, CLHEP::HepRandomEngine *)
double timeOfFlight(const DetId &detId) const
float & preciseAtMod(int i)
mutable function to access precise samples
Definition: CaloSamples.h:31
virtual void add(const PCaloHit &hit, CLHEP::HepRandomEngine *)
process a single SimHit
std::map< int, HcalSiPMShape > shapeMap
static const double tzero[3]
HcalSiPMHitResponse(const CaloVSimParameterMap *parameterMap, const CaloShapes *shapes, bool PreMix1=false, bool HighFidelity=true)
const CaloVHitFilter * theHitFilter
photonTimeMap precisionTimedPhotons
void setPreciseSize(unsigned int size)
Definition: CaloSamples.h:60
double photoelectronsToAnalog(const DetId &detId) const override
std::vector< float > sipmNonlinearity(const DetId &detId) const
#define LogDebug(id)
double sipmTau() const