CMS 3D CMS Logo

BTLElectronicsSim.cc
Go to the documentation of this file.
2 
5 
6 #include "CLHEP/Random/RandPoissonQ.h"
7 #include "CLHEP/Random/RandGaussQ.h"
8 
9 #include "Math/ChebyshevPol.h"
10 
11 using namespace mtd;
12 
14  : debug_(pset.getUntrackedParameter<bool>("debug", false)),
15  bxTime_(pset.getParameter<double>("bxTime")),
16  testBeamMIPTimeRes_(pset.getParameter<double>("TestBeamMIPTimeRes")),
17  ScintillatorRiseTime_(pset.getParameter<double>("ScintillatorRiseTime")),
18  ScintillatorDecayTime_(pset.getParameter<double>("ScintillatorDecayTime")),
19  ChannelTimeOffset_(pset.getParameter<double>("ChannelTimeOffset")),
20  smearChannelTimeOffset_(pset.getParameter<double>("smearChannelTimeOffset")),
21  EnergyThreshold_(pset.getParameter<double>("EnergyThreshold")),
22  TimeThreshold1_(pset.getParameter<double>("TimeThreshold1")),
23  TimeThreshold2_(pset.getParameter<double>("TimeThreshold2")),
24  ReferencePulseNpe_(pset.getParameter<double>("ReferencePulseNpe")),
25  SinglePhotonTimeResolution_(pset.getParameter<double>("SinglePhotonTimeResolution")),
26  DarkCountRate_(pset.getParameter<double>("DarkCountRate")),
27  SigmaElectronicNoise_(pset.getParameter<double>("SigmaElectronicNoise")),
28  SigmaClock_(pset.getParameter<double>("SigmaClock")),
29  smearTimeForOOTtails_(pset.getParameter<bool>("SmearTimeForOOTtails")),
30  Npe_to_pC_(pset.getParameter<double>("Npe_to_pC")),
31  Npe_to_V_(pset.getParameter<double>("Npe_to_V")),
32  sigmaRelTOFHIRenergy_(pset.getParameter<std::vector<double>>("SigmaRelTOFHIRenergy")),
33  adcNbits_(pset.getParameter<uint32_t>("adcNbits")),
34  tdcNbits_(pset.getParameter<uint32_t>("tdcNbits")),
35  adcSaturation_MIP_(pset.getParameter<double>("adcSaturation_MIP")),
36  adcBitSaturation_(std::pow(2, adcNbits_) - 1),
37  adcLSB_MIP_(adcSaturation_MIP_ / adcBitSaturation_),
38  adcThreshold_MIP_(pset.getParameter<double>("adcThreshold_MIP")),
39  toaLSB_ns_(pset.getParameter<double>("toaLSB_ns")),
40  tdcBitSaturation_(std::pow(2, tdcNbits_) - 1),
41  CorrCoeff_(pset.getParameter<double>("CorrelationCoefficient")),
42  cosPhi_(0.5 * (sqrt(1. + CorrCoeff_) + sqrt(1. - CorrCoeff_))),
43  sinPhi_(0.5 * CorrCoeff_ / cosPhi_),
44  ScintillatorDecayTime2_(ScintillatorDecayTime_ * ScintillatorDecayTime_),
45  ScintillatorDecayTimeInv_(1. / ScintillatorDecayTime_),
46  SPTR2_(SinglePhotonTimeResolution_ * SinglePhotonTimeResolution_),
47  DCRxRiseTime_(DarkCountRate_ * ScintillatorRiseTime_),
48  SigmaElectronicNoise2_(SigmaElectronicNoise_ * SigmaElectronicNoise_),
49  SigmaClock2_(SigmaClock_ * SigmaClock_) {}
50 
53  CLHEP::HepRandomEngine* hre) const {
54  MTDSimHitData chargeColl, toa1, toa2;
55 
56  for (MTDSimHitDataAccumulator::const_iterator it = input.begin(); it != input.end(); it++) {
57  // --- Digitize only the in-time bucket:
58  const unsigned int iBX = mtd_digitizer::kInTimeBX;
59 
60  chargeColl.fill(0.f);
61  toa1.fill(0.f);
62  toa2.fill(0.f);
63  for (size_t iside = 0; iside < 2; iside++) {
64  // --- Fluctuate the total number of photo-electrons
65  float Npe = CLHEP::RandPoissonQ::shoot(hre, (it->second).hit_info[2 * iside][iBX]);
66  if (Npe < EnergyThreshold_)
67  continue;
68 
69  // --- Get the time of arrival and add a channel time offset
70  float finalToA1 = (it->second).hit_info[1 + 2 * iside][iBX] + ChannelTimeOffset_;
71 
72  if (smearChannelTimeOffset_ > 0.) {
73  float timeSmearing = CLHEP::RandGaussQ::shoot(hre, 0., smearChannelTimeOffset_);
74  finalToA1 += timeSmearing;
75  }
76 
77  // --- Calculate and add the time walk: the time of arrival is read in correspondence
78  // with two thresholds on the signal pulse
79  std::array<float, 3> times =
81 
82  // --- If the pulse amplitude is smaller than TimeThreshold2, the trigger does not fire
83  if (times[1] == 0.)
84  continue;
85 
86  float finalToA2 = finalToA1 + times[1];
87  finalToA1 += times[0];
88 
89  // --- Estimate the time uncertainty due to photons from earlier OOT hits in the current BTL cell
91  float rate_oot = 0.;
92  // Loop on earlier OOT hits
93  for (int ibx = 0; ibx < mtd_digitizer::kInTimeBX; ++ibx) {
94  if ((it->second).hit_info[2 * iside][ibx] > 0.) {
95  float hit_time = (it->second).hit_info[1 + 2 * iside][ibx] + bxTime_ * (ibx - mtd_digitizer::kInTimeBX);
96  float npe_oot = CLHEP::RandPoissonQ::shoot(hre, (it->second).hit_info[2 * iside][ibx]);
97  rate_oot += npe_oot * exp(hit_time * ScintillatorDecayTimeInv_) * ScintillatorDecayTimeInv_;
98  }
99  } // ibx loop
100 
101  if (rate_oot > 0.) {
102  float sigma_oot = sqrt(rate_oot * ScintillatorRiseTime_) * ScintillatorDecayTime_ / Npe;
103  float smearing_oot = CLHEP::RandGaussQ::shoot(hre, 0., sigma_oot);
104  finalToA1 += smearing_oot;
105  finalToA2 += smearing_oot;
106  }
107  } // if smearTimeForOOTtails_
108 
109  // --- Uncertainty due to the fluctuations of the n-th photon arrival time:
110  if (testBeamMIPTimeRes_ > 0.) {
111  // In this case the time resolution is parametrized from the testbeam.
112  // The same parameterization is used for both thresholds.
113  float sigma = testBeamMIPTimeRes_ / sqrt(Npe);
114  float smearing_stat_thr1 = CLHEP::RandGaussQ::shoot(hre, 0., sigma);
115  float smearing_stat_thr2 = CLHEP::RandGaussQ::shoot(hre, 0., sigma);
116 
117  finalToA1 += smearing_stat_thr1;
118  finalToA2 += smearing_stat_thr2;
119 
120  } else {
121  // In this case the time resolution is taken from the literature.
122  // The fluctuations due to the first TimeThreshold1_ p.e. are common to both times
123  float smearing_stat_thr1 =
124  CLHEP::RandGaussQ::shoot(hre, 0., ScintillatorDecayTime_ * sqrt(sigma2_pe(TimeThreshold1_, Npe)));
125  float smearing_stat_thr2 = CLHEP::RandGaussQ::shoot(
127  finalToA1 += smearing_stat_thr1;
128  finalToA2 += smearing_stat_thr1 + smearing_stat_thr2;
129  }
130 
131  // --- Add in quadrature the uncertainties due to the SiPM timing resolution, the SiPM DCR,
132  // the electronic noise and the clock distribution:
133  float slew2 = ScintillatorDecayTime2_ / Npe / Npe;
134 
135  float sigma2_tot_thr1 =
137  float sigma2_tot_thr2 =
139 
140  // --- Smear the arrival times using the correlated uncertainties:
141  float smearing_thr1_uncorr = CLHEP::RandGaussQ::shoot(hre, 0., sqrt(sigma2_tot_thr1));
142  float smearing_thr2_uncorr = CLHEP::RandGaussQ::shoot(hre, 0., sqrt(sigma2_tot_thr2));
143 
144  finalToA1 += cosPhi_ * smearing_thr1_uncorr + sinPhi_ * smearing_thr2_uncorr;
145  finalToA2 += sinPhi_ * smearing_thr1_uncorr + cosPhi_ * smearing_thr2_uncorr;
146 
147  //Smear the energy according to TOFHIR energy branch measured resolution
148  float tofhir_ampnoise_relsigma = ROOT::Math::Chebyshev4(Npe,
154  float smearing_tofhir = CLHEP::RandGaussQ::shoot(hre, 0., tofhir_ampnoise_relsigma);
155  // the amplitude resolution already includes the photostatistics fluctuation, use the original average deposit
156  chargeColl[iside] = (it->second).hit_info[2 * iside][iBX] * Npe_to_pC_ *
157  (1. + smearing_tofhir); // the p.e. number is here converted to pC
158 
159  toa1[iside] = finalToA1;
160  toa2[iside] = finalToA2;
161 
162  } // iside loop
163 
164  //run the shaper to create a new data frame
165  BTLDataFrame rawDataFrame(it->first.detid_);
166  runTrivialShaper(rawDataFrame, chargeColl, toa1, toa2, it->first.row_, it->first.column_);
167  updateOutput(output, rawDataFrame);
168 
169  } // MTDSimHitDataAccumulator loop
170 }
171 
173  const mtd::MTDSimHitData& chargeColl,
174  const mtd::MTDSimHitData& toa1,
175  const mtd::MTDSimHitData& toa2,
176  const uint8_t row,
177  const uint8_t col) const {
178  bool debug = debug_;
179 #ifdef EDM_ML_DEBUG
180  for (int it = 0; it < (int)(chargeColl.size()); it++)
181  debug |= (chargeColl[it] > adcThreshold_MIP_);
182 #endif
183 
184  if (debug)
185  edm::LogVerbatim("BTLElectronicsSim") << "[runTrivialShaper]" << std::endl;
186 
187  //set new ADCs
188  for (int it = 0; it < (int)(chargeColl.size()); it++) {
189  BTLSample newSample;
190  newSample.set(false, false, 0, 0, 0, row, col);
191 
192  //brute force saturation, maybe could to better with an exponential like saturation
193  const uint32_t adc = std::min((uint32_t)std::floor(chargeColl[it] / adcLSB_MIP_), adcBitSaturation_);
194  const uint32_t tdc_time1 = std::min((uint32_t)std::floor(toa1[it] / toaLSB_ns_), tdcBitSaturation_);
195  const uint32_t tdc_time2 = std::min((uint32_t)std::floor(toa2[it] / toaLSB_ns_), tdcBitSaturation_);
196 
197  newSample.set(
198  chargeColl[it] > adcThreshold_MIP_, tdc_time1 == tdcBitSaturation_, tdc_time2, tdc_time1, adc, row, col);
199  dataFrame.setSample(it, newSample);
200 
201  if (debug)
202  edm::LogVerbatim("BTLElectronicsSim") << adc << " (" << chargeColl[it] << "/" << adcLSB_MIP_ << ") ";
203  }
204 
205  if (debug) {
206  std::ostringstream msg;
207  dataFrame.print(msg);
208  edm::LogVerbatim("BTLElectronicsSim") << msg.str() << std::endl;
209  }
210 }
211 
212 void BTLElectronicsSim::updateOutput(BTLDigiCollection& coll, const BTLDataFrame& rawDataFrame) const {
213  BTLDataFrame dataFrame(rawDataFrame.id());
214  dataFrame.resize(dfSIZE);
215  bool putInEvent(false);
216  for (int it = 0; it < dfSIZE; ++it) {
217  dataFrame.setSample(it, rawDataFrame[it]);
218  if (it == 0)
219  putInEvent = rawDataFrame[it].threshold();
220  }
221 
222  if (putInEvent) {
223  coll.push_back(dataFrame);
224  }
225 }
226 
227 float BTLElectronicsSim::sigma2_pe(const float& Q, const float& R) const {
228  float OneOverR = 1. / R;
229  float OneOverR2 = OneOverR * OneOverR;
230 
231  // --- This is Eq. (17) from Nucl. Instr. Meth. A 564 (2006) 185
232  float sigma2 = Q * OneOverR2 *
233  (1. + 2. * (Q + 1.) * OneOverR + (Q + 1.) * (6. * Q + 11) * OneOverR2 +
234  (Q + 1.) * (Q + 2.) * (2. * Q + 5.) * OneOverR2 * OneOverR);
235 
236  return sigma2;
237 }
Log< level::Info, true > LogVerbatim
std::array< float, 3 > timeAtThr(const float scale, const float threshold1, const float threshold2) const
Definition: MTDShapeBase.cc:9
const float Npe_to_pC_
const float DCRxRiseTime_
const float adcThreshold_MIP_
std::array< MTDSimData_t, nSamples > MTDSimHitData
const bool smearTimeForOOTtails_
void updateOutput(BTLDigiCollection &coll, const BTLDataFrame &rawDataFrame) const
void push_back(T const &t)
std::unordered_map< MTDCellId, MTDCellInfo > MTDSimHitDataAccumulator
const float ScintillatorDecayTimeInv_
const float TimeThreshold2_
wrapper for a data word
Definition: BTLSample.h:13
const float adcLSB_MIP_
static constexpr int dfSIZE
static std::string const input
Definition: EdmProvDump.cc:50
const float ScintillatorDecayTime2_
const std::vector< double > sigmaRelTOFHIRenergy_
const float toaLSB_ns_
void runTrivialShaper(BTLDataFrame &dataFrame, const mtd::MTDSimHitData &chargeColl, const mtd::MTDSimHitData &toa1, const mtd::MTDSimHitData &toa2, const uint8_t row, const uint8_t col) const
float sigma2_pe(const float &Q, const float &R) const
const BTLPulseShape btlPulseShape_
void resize(size_t s)
allow to set size
Definition: FTLDataFrameT.h:51
T sqrt(T t)
Definition: SSEVec.h:19
const D & id() const
det id
Definition: FTLDataFrameT.h:31
const uint32_t adcBitSaturation_
double f[11][100]
void setSample(int i, const S &sample)
Definition: FTLDataFrameT.h:58
const float SigmaElectronicNoise2_
#define debug
Definition: HDRShower.cc:19
constexpr int kInTimeBX
const float EnergyThreshold_
tuple msg
Definition: mps_check.py:286
BTLElectronicsSim(const edm::ParameterSet &pset, edm::ConsumesCollector iC)
const uint32_t tdcBitSaturation_
const float ScintillatorDecayTime_
const float TimeThreshold1_
void set(bool thr, bool mode, uint16_t toa2, uint16_t toa, uint16_t data, uint8_t row, uint8_t col)
Definition: BTLSample.h:37
const float ChannelTimeOffset_
col
Definition: cuy.py:1009
Readout digi for HGC.
Definition: FTLDataFrameT.h:14
const float ScintillatorRiseTime_
const float testBeamMIPTimeRes_
const float smearChannelTimeOffset_
void print(std::ostream &out=std::cout)
Definition: FTLDataFrameT.h:62
void run(const mtd::MTDSimHitDataAccumulator &input, BTLDigiCollection &output, CLHEP::HepRandomEngine *hre) const
const float SigmaClock2_
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
uint16_t *__restrict__ uint16_t const *__restrict__ adc
const float ReferencePulseNpe_