CMS 3D CMS Logo

List of all members | Public Types | Public Member Functions | Private Attributes
HGCFEElectronics< DFr > Class Template Reference

models the behavior of the front-end electronics More...

#include <HGCFEElectronics.h>

Public Types

enum  HGCFEElectronicsFirmwareVersion { TRIVIAL, SIMPLE, WITHTOT }
 
enum  HGCFEElectronicsTOTMode { WEIGHTEDBYE, SIMPLETHRESHOLD }
 

Public Member Functions

float getADClsb ()
 returns the LSB in MIP currently configured More...
 
float getADCThreshold ()
 
hgc_digi::FEADCPulseShapegetDefaultADCPulse ()
 getter for the default ADC pulse configured by python More...
 
int getTargetMipValue ()
 
std::array< float, 3 > getTDCForToAOnset ()
 
float getTDClsb ()
 
float getTDCOnset ()
 
float getTimeJitter (float totalCharge, int thickness)
 
 HGCFEElectronics (const edm::ParameterSet &ps)
 CTOR. More...
 
void runShaper (DFr &dataFrame, hgc::HGCSimHitData &chargeColl, hgc::HGCSimHitData &toa, CLHEP::HepRandomEngine *engine, uint32_t thrADC=0, float lsbADC=-1, uint32_t gainIdx=0, float maxADC=-1, int thickness=1)
 
void runShaper (DFr &dataFrame, hgc::HGCSimHitData &chargeColl, hgc::HGCSimHitData &toa, const hgc_digi::FEADCPulseShape &adcPulse, CLHEP::HepRandomEngine *engine, uint32_t thrADC=0, float lsbADC=-1, uint32_t gainIdx=0, float maxADC=-1, int thickness=1)
 switches according to the firmware version More...
 
void runShaperWithToT (DFr &dataFrame, hgc::HGCSimHitData &chargeColl, hgc::HGCSimHitData &toa, CLHEP::HepRandomEngine *engine, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC, int thickness)
 
void runShaperWithToT (DFr &dataFrame, hgc::HGCSimHitData &chargeColl, hgc::HGCSimHitData &toa, CLHEP::HepRandomEngine *engine, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC, int thickness, const hgc_digi::FEADCPulseShape &adcPulse)
 implements pulse shape and switch to time over threshold including deadtime More...
 
void runSimpleShaper (DFr &dataFrame, hgc::HGCSimHitData &chargeColl, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC)
 
void runSimpleShaper (DFr &dataFrame, hgc::HGCSimHitData &chargeColl, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC, const hgc_digi::FEADCPulseShape &adcPulse)
 applies a shape to each time sample and propagates the tails to the subsequent time samples More...
 
void runTrivialShaper (DFr &dataFrame, hgc::HGCSimHitData &chargeColl, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC)
 converts charge to digis without pulse shape More...
 
void setADClsb (float newLSB)
 
void SetNoiseValues (const std::vector< float > &noise_fC)
 
uint32_t toaMode () const
 returns how ToT will be computed More...
 
 ~HGCFEElectronics ()
 DTOR. More...
 

Private Attributes

float adcLSB_fC_
 
hgc_digi::FEADCPulseShape adcPulse_
 
float adcSaturation_fC_
 
float adcThreshold_fC_
 
std::array< bool, hgc::nSamples > busyFlags
 
uint32_t fwVersion_
 
std::array< float, 3 > jitterConstant2_ns_
 
std::array< float, 3 > jitterNoise2_ns_
 
hgc::HGCSimHitData newCharge
 
std::vector< float > noise_fC_
 
hgc_digi::FEADCPulseShape pulseAvgT_
 
uint32_t targetMIPvalue_ADC_
 
std::vector< float > tdcChargeDrainParameterisation_
 
std::array< float, 3 > tdcForToAOnset_fC_
 
float tdcLSB_fC_
 
float tdcOnset_fC_
 
float tdcResolutionInNs_
 
float tdcSaturation_fC_
 
bool thresholdFollowsMIP_
 
std::array< bool, hgc::nSamples > toaFlags
 
hgc::HGCSimHitData toaFromToT
 
float toaLSB_ns_
 
uint32_t toaMode_
 
std::array< bool, hgc::nSamples > totFlags
 

Detailed Description

template<class DFr>
class HGCFEElectronics< DFr >

models the behavior of the front-end electronics

Definition at line 24 of file HGCFEElectronics.h.

Member Enumeration Documentation

◆ HGCFEElectronicsFirmwareVersion

Enumerator
TRIVIAL 
SIMPLE 
WITHTOT 

Definition at line 26 of file HGCFEElectronics.h.

26 { TRIVIAL, SIMPLE, WITHTOT };

◆ HGCFEElectronicsTOTMode

template<class DFr >
enum HGCFEElectronics::HGCFEElectronicsTOTMode
Enumerator
WEIGHTEDBYE 
SIMPLETHRESHOLD 

Definition at line 27 of file HGCFEElectronics.h.

Constructor & Destructor Documentation

◆ HGCFEElectronics()

template<class DFr >
HGCFEElectronics< DFr >::HGCFEElectronics ( const edm::ParameterSet ps)

CTOR.

Definition at line 11 of file HGCFEElectronics.cc.

12  : fwVersion_{ps.getParameter<uint32_t>("fwVersion")},
13  adcPulse_{},
14  pulseAvgT_{},
16  adcSaturation_fC_{-1.0},
17  adcLSB_fC_{},
18  tdcLSB_fC_{},
19  tdcSaturation_fC_{-1.0},
21  tdcOnset_fC_{},
22  toaLSB_ns_{},
23  tdcResolutionInNs_{1e-9}, // set time resolution very small by default
27  noise_fC_{},
29  edm::LogVerbatim("HGCFE") << "[HGCFEElectronics] running with version " << fwVersion_ << std::endl;
30  if (ps.exists("adcPulse")) {
31  auto temp = ps.getParameter<std::vector<double> >("adcPulse");
32  for (unsigned i = 0; i < temp.size(); ++i) {
33  adcPulse_[i] = (float)temp[i];
34  }
35  // normalize adc pulse
36  for (unsigned i = 0; i < adcPulse_.size(); ++i) {
37  adcPulse_[i] = adcPulse_[i] / adcPulse_[2];
38  }
39  temp = ps.getParameter<std::vector<double> >("pulseAvgT");
40  for (unsigned i = 0; i < temp.size(); ++i) {
41  pulseAvgT_[i] = (float)temp[i];
42  }
43  }
44  if (ps.exists("adcNbits")) {
45  uint32_t adcNbits = ps.getParameter<uint32_t>("adcNbits");
46  adcSaturation_fC_ = ps.getParameter<double>("adcSaturation_fC");
48  edm::LogVerbatim("HGCFE") << "[HGCFEElectronics] " << adcNbits << " bit ADC defined"
49  << " with LSB=" << adcLSB_fC_ << " saturation to occur @ " << adcSaturation_fC_
50  << std::endl;
51  }
52 
53  if (ps.exists("tdcNbits")) {
54  uint32_t tdcNbits = ps.getParameter<uint32_t>("tdcNbits");
55  tdcSaturation_fC_ = ps.getParameter<double>("tdcSaturation_fC");
57  // lower tdcSaturation_fC_ by one part in a million
58  // to ensure largest charge converted in bits is 0xfff and not 0x000
59  tdcSaturation_fC_ *= (1. - 1e-6);
60  edm::LogVerbatim("HGCFE") << "[HGCFEElectronics] " << tdcNbits << " bit TDC defined with LSB=" << tdcLSB_fC_
61  << " saturation to occur @ " << tdcSaturation_fC_
62  << " (NB lowered by 1 part in a million)" << std::endl;
63  }
64  if (ps.exists("targetMIPvalue_ADC"))
65  targetMIPvalue_ADC_ = ps.getParameter<uint32_t>("targetMIPvalue_ADC");
66  if (ps.exists("adcThreshold_fC"))
67  adcThreshold_fC_ = ps.getParameter<double>("adcThreshold_fC");
68  if (ps.exists("tdcOnset_fC"))
69  tdcOnset_fC_ = ps.getParameter<double>("tdcOnset_fC");
70  if (ps.exists("tdcForToAOnset_fC")) {
71  auto temp = ps.getParameter<std::vector<double> >("tdcForToAOnset_fC");
72  if (temp.size() == tdcForToAOnset_fC_.size()) {
73  std::copy_n(temp.begin(), temp.size(), tdcForToAOnset_fC_.begin());
74  } else {
75  throw cms::Exception("BadConfiguration") << " HGCFEElectronics wrong size for ToA thresholds ";
76  }
77  }
78  if (ps.exists("toaLSB_ns"))
79  toaLSB_ns_ = ps.getParameter<double>("toaLSB_ns");
80  if (ps.exists("tdcChargeDrainParameterisation")) {
81  for (auto val : ps.getParameter<std::vector<double> >("tdcChargeDrainParameterisation")) {
82  tdcChargeDrainParameterisation_.push_back((float)val);
83  }
84  }
85  if (ps.exists("tdcResolutionInPs"))
86  tdcResolutionInNs_ = ps.getParameter<double>("tdcResolutionInPs") * 1e-3; // convert to ns
87  if (ps.exists("toaMode"))
88  toaMode_ = ps.getParameter<uint32_t>("toaMode");
89 
90  if (ps.exists("jitterNoise_ns")) {
91  auto temp = ps.getParameter<std::vector<double> >("jitterNoise_ns");
92  if (temp.size() == jitterNoise2_ns_.size()) {
93  std::copy_n(temp.begin(), temp.size(), jitterNoise2_ns_.begin());
94  } else {
95  throw cms::Exception("BadConfiguration") << " HGCFEElectronics wrong size for ToA jitterNoise ";
96  }
97  }
98  if (ps.exists("jitterConstant_ns")) {
99  auto temp = ps.getParameter<std::vector<double> >("jitterConstant_ns");
100  if (temp.size() == jitterConstant2_ns_.size()) {
101  std::copy_n(temp.begin(), temp.size(), jitterConstant2_ns_.begin());
102  } else {
103  throw cms::Exception("BadConfiguration") << " HGCFEElectronics wrong size for ToA jitterConstant ";
104  }
105  }
106 }

References edm::ParameterSet::getParameter().

◆ ~HGCFEElectronics()

template<class DFr >
HGCFEElectronics< DFr >::~HGCFEElectronics ( )
inline

DTOR.

Definition at line 156 of file HGCFEElectronics.h.

156 {}

Member Function Documentation

◆ getADClsb()

template<class DFr >
float HGCFEElectronics< DFr >::getADClsb ( )
inline

returns the LSB in MIP currently configured

Definition at line 89 of file HGCFEElectronics.h.

89 { return adcLSB_fC_; }

References HGCFEElectronics< DFr >::adcLSB_fC_.

◆ getADCThreshold()

template<class DFr >
float HGCFEElectronics< DFr >::getADCThreshold ( )
inline

Definition at line 92 of file HGCFEElectronics.h.

92 { return adcThreshold_fC_; }

References HGCFEElectronics< DFr >::adcThreshold_fC_.

◆ getDefaultADCPulse()

template<class DFr >
hgc_digi::FEADCPulseShape& HGCFEElectronics< DFr >::getDefaultADCPulse ( )
inline

getter for the default ADC pulse configured by python

Definition at line 151 of file HGCFEElectronics.h.

151 { return adcPulse_; }

References HGCFEElectronics< DFr >::adcPulse_.

◆ getTargetMipValue()

template<class DFr >
int HGCFEElectronics< DFr >::getTargetMipValue ( )
inline

Definition at line 91 of file HGCFEElectronics.h.

91 { return targetMIPvalue_ADC_; }

References HGCFEElectronics< DFr >::targetMIPvalue_ADC_.

◆ getTDCForToAOnset()

template<class DFr >
std::array<float, 3> HGCFEElectronics< DFr >::getTDCForToAOnset ( )
inline

Definition at line 94 of file HGCFEElectronics.h.

94 { return tdcForToAOnset_fC_; }

References HGCFEElectronics< DFr >::tdcForToAOnset_fC_.

◆ getTDClsb()

template<class DFr >
float HGCFEElectronics< DFr >::getTDClsb ( )
inline

Definition at line 90 of file HGCFEElectronics.h.

90 { return tdcLSB_fC_; }

References HGCFEElectronics< DFr >::tdcLSB_fC_.

◆ getTDCOnset()

template<class DFr >
float HGCFEElectronics< DFr >::getTDCOnset ( )
inline

Definition at line 93 of file HGCFEElectronics.h.

93 { return tdcOnset_fC_; }

References HGCFEElectronics< DFr >::tdcOnset_fC_.

◆ getTimeJitter()

template<class DFr >
float HGCFEElectronics< DFr >::getTimeJitter ( float  totalCharge,
int  thickness 
)
inline

Definition at line 78 of file HGCFEElectronics.h.

78  {
79  float A2 = jitterNoise2_ns_.at(thickness - 1);
80  float C2 = jitterConstant2_ns_.at(thickness - 1);
81  float X2 = pow((totalCharge / noise_fC_.at(thickness - 1)), 2.);
82  float jitter2 = A2 / X2 + C2;
83  return sqrt(jitter2);
84  };

References HGCFEElectronics< DFr >::jitterConstant2_ns_, HGCFEElectronics< DFr >::jitterNoise2_ns_, HGCFEElectronics< DFr >::noise_fC_, funct::pow(), mathSSE::sqrt(), and Calorimetry_cff::thickness.

◆ runShaper() [1/2]

template<class DFr >
void HGCFEElectronics< DFr >::runShaper ( DFr &  dataFrame,
hgc::HGCSimHitData chargeColl,
hgc::HGCSimHitData toa,
CLHEP::HepRandomEngine *  engine,
uint32_t  thrADC = 0,
float  lsbADC = -1,
uint32_t  gainIdx = 0,
float  maxADC = -1,
int  thickness = 1 
)
inline

Definition at line 62 of file HGCFEElectronics.h.

70  {
71  runShaper(dataFrame, chargeColl, toa, adcPulse_, engine, thrADC, lsbADC, gainIdx, maxADC, thickness);
72  }

References HGCFEElectronics< DFr >::adcPulse_, HGCFEElectronics< DFr >::runShaper(), and Calorimetry_cff::thickness.

◆ runShaper() [2/2]

template<class DFr >
void HGCFEElectronics< DFr >::runShaper ( DFr &  dataFrame,
hgc::HGCSimHitData chargeColl,
hgc::HGCSimHitData toa,
const hgc_digi::FEADCPulseShape adcPulse,
CLHEP::HepRandomEngine *  engine,
uint32_t  thrADC = 0,
float  lsbADC = -1,
uint32_t  gainIdx = 0,
float  maxADC = -1,
int  thickness = 1 
)
inline

switches according to the firmware version

Definition at line 37 of file HGCFEElectronics.h.

46  {
47  switch (fwVersion_) {
48  case SIMPLE: {
49  runSimpleShaper(dataFrame, chargeColl, thrADC, lsbADC, gainIdx, maxADC, adcPulse);
50  break;
51  }
52  case WITHTOT: {
53  runShaperWithToT(dataFrame, chargeColl, toa, engine, thrADC, lsbADC, gainIdx, maxADC, thickness, adcPulse);
54  break;
55  }
56  default: {
57  runTrivialShaper(dataFrame, chargeColl, thrADC, lsbADC, gainIdx, maxADC);
58  break;
59  }
60  }
61  }

References hgcROCParameters_cfi::adcPulse, HGCFEElectronics< DFr >::fwVersion_, HGCFEElectronics< DFr >::runShaperWithToT(), HGCFEElectronics< DFr >::runSimpleShaper(), HGCFEElectronics< DFr >::runTrivialShaper(), HGCFEElectronics< DFr >::SIMPLE, Calorimetry_cff::thickness, and HGCFEElectronics< DFr >::WITHTOT.

Referenced by HGCFEElectronics< DFr >::runShaper().

◆ runShaperWithToT() [1/2]

template<class DFr >
void HGCFEElectronics< DFr >::runShaperWithToT ( DFr &  dataFrame,
hgc::HGCSimHitData chargeColl,
hgc::HGCSimHitData toa,
CLHEP::HepRandomEngine *  engine,
uint32_t  thrADC,
float  lsbADC,
uint32_t  gainIdx,
float  maxADC,
int  thickness 
)
inline

Definition at line 131 of file HGCFEElectronics.h.

139  {
140  runShaperWithToT(dataFrame, chargeColl, toa, engine, thrADC, lsbADC, gainIdx, maxADC, thickness, adcPulse_);
141  }

References HGCFEElectronics< DFr >::adcPulse_, HGCFEElectronics< DFr >::runShaperWithToT(), and Calorimetry_cff::thickness.

◆ runShaperWithToT() [2/2]

template<class DFr >
void HGCFEElectronics< DFr >::runShaperWithToT ( DFr &  dataFrame,
hgc::HGCSimHitData chargeColl,
hgc::HGCSimHitData toa,
CLHEP::HepRandomEngine *  engine,
uint32_t  thrADC,
float  lsbADC,
uint32_t  gainIdx,
float  maxADC,
int  thickness,
const hgc_digi::FEADCPulseShape adcPulse 
)

implements pulse shape and switch to time over threshold including deadtime

Definition at line 207 of file HGCFEElectronics.cc.

216  {
217  busyFlags.fill(false);
218  totFlags.fill(false);
219  toaFlags.fill(false);
220  newCharge.fill(0.f);
221  toaFromToT.fill(0.f);
222 
223 #ifdef EDM_ML_DEBUG
224  constexpr bool debug_state(true);
225 #else
226  constexpr bool debug_state(false);
227 #endif
228 
229  bool debug = debug_state;
230  float timeToA = 0.f;
231 
232  //first look at time
233  //for pileup look only at intime signals
234  //ToA is in central BX if fired -- std::floor(BX/25.)+9;
235  int fireBX = 9;
236  //noise fluctuation on charge is added after ToA computation
237  //do not recheck the ToA firing threshold tdcForToAOnset_fC_[thickness-1] not to bias the efficiency
238  //to be done properly with realistic ToA shaper and jitter for the moment accounted in the smearing
239  if (toaColl[fireBX] != 0.f) {
240  timeToA = toaColl[fireBX];
241  float jitter = getTimeJitter(chargeColl[fireBX], thickness);
242  if (jitter != 0)
243  timeToA = CLHEP::RandGaussQ::shoot(engine, timeToA, jitter);
244  else if (tdcResolutionInNs_ != 0)
245  timeToA = CLHEP::RandGaussQ::shoot(engine, timeToA, tdcResolutionInNs_);
246  if (timeToA >= 0.f && timeToA <= 25.f)
247  toaFlags[fireBX] = true;
248  }
249 
250  //now look at charge
251  //first identify bunches which will trigger ToT
252  //if(debug_state) edm::LogVerbatim("HGCFE") << "[runShaperWithToT]" << std::endl;
253  for (int it = 0; it < (int)(chargeColl.size()); ++it) {
254  debug = debug_state;
255  //if already flagged as busy it can't be re-used to trigger the ToT
256  if (busyFlags[it])
257  continue;
258 
259  //if below TDC onset will be handled by SARS ADC later
260  float charge = chargeColl[it];
261  if (charge < tdcOnset_fC_) {
262  debug = false;
263  continue;
264  }
265 
266  //raise TDC mode for charge computation
267  //ToA anyway fired independently will be sorted out with realistic ToA dedicated shaper
268  float toa = timeToA;
269  totFlags[it] = true;
270 
271  if (debug)
272  edm::LogVerbatim("HGCFE") << "\t q=" << charge << " fC with <toa>=" << toa << " ns, triggers ToT @ " << it
273  << std::endl;
274 
275  //compute total charge to be integrated and integration time
276  //needs a loop as ToT will last as long as there is charge to dissipate
277  int busyBxs(0);
278  float totalCharge(charge), finalToA(toa), integTime(0);
279  while (true) {
280  //compute integration time in ns and # bunches
281  //float newIntegTime(0);
282  int poffset = 0;
283  float charge_offset = 0.f;
284  const float charge_kfC(totalCharge * 1e-3);
285  if (charge_kfC < tdcChargeDrainParameterisation_[3]) {
286  //newIntegTime=tdcChargeDrainParameterisation_[0]*pow(charge_kfC,2)+tdcChargeDrainParameterisation_[1]*charge_kfC+tdcChargeDrainParameterisation_[2];
287  } else if (charge_kfC < tdcChargeDrainParameterisation_[7]) {
288  poffset = 4;
289  charge_offset = tdcChargeDrainParameterisation_[3];
290  //newIntegTime=tdcChargeDrainParameterisation_[4]*pow(charge_kfC-tdcChargeDrainParameterisation_[3],2)+tdcChargeDrainParameterisation_[5]*(charge_kfC-tdcChargeDrainParameterisation_[3])+tdcChargeDrainParameterisation_[6];
291  } else {
292  poffset = 8;
293  charge_offset = tdcChargeDrainParameterisation_[7];
294  //newIntegTime=tdcChargeDrainParameterisation_[8]*pow(charge_kfC-tdcChargeDrainParameterisation_[7],2)+tdcChargeDrainParameterisation_[9]*(charge_kfC-tdcChargeDrainParameterisation_[7])+tdcChargeDrainParameterisation_[10];
295  }
296  const float charge_mod = charge_kfC - charge_offset;
297  const float newIntegTime =
298  ((tdcChargeDrainParameterisation_[poffset] * charge_mod + tdcChargeDrainParameterisation_[poffset + 1]) *
299  charge_mod +
300  tdcChargeDrainParameterisation_[poffset + 2]);
301 
302  const int newBusyBxs = std::floor(newIntegTime / 25.f) + 1;
303 
304  //if no update is needed regarding the number of bunches,
305  //then the ToT integration time has converged
306  integTime = newIntegTime;
307  if (newBusyBxs == busyBxs)
308  break;
309 
310  //update charge integrated during ToT
311  if (debug) {
312  if (busyBxs == 0)
313  edm::LogVerbatim("HGCFE") << "\t Intial busy estimate=" << integTime << " ns = " << newBusyBxs << " bxs"
314  << std::endl;
315  else
316  edm::LogVerbatim("HGCFE") << "\t ...integrated charge overflows initial busy estimate, interating again"
317  << std::endl;
318  }
319 
320  //update number of busy bunches
321  busyBxs = newBusyBxs;
322 
323  //reset charge to be integrated
324  totalCharge = charge;
325  if (toaMode_ == WEIGHTEDBYE)
326  finalToA = toa * charge;
327 
328  //add leakage from previous bunches in SARS ADC mode
329  for (int jt = 0; jt < it; ++jt) {
330  const unsigned int deltaT = (it - jt);
331  if ((deltaT + 2) >= adcPulse.size() || chargeColl[jt] == 0.f || totFlags[jt] || busyFlags[jt])
332  continue;
333 
334  const float leakCharge = chargeColl[jt] * adcPulse[deltaT + 2];
335  totalCharge += leakCharge;
336  if (toaMode_ == WEIGHTEDBYE)
337  finalToA += leakCharge * pulseAvgT_[deltaT + 2];
338 
339  if (debug)
340  edm::LogVerbatim("HGCFE") << "\t\t leaking " << chargeColl[jt] << " fC @ deltaT=-" << deltaT << " -> +"
341  << leakCharge << " with avgT=" << pulseAvgT_[deltaT + 2] << std::endl;
342  }
343 
344  //add contamination from posterior bunches
345  for (int jt = it + 1; jt < it + busyBxs && jt < dataFrame.size(); ++jt) {
346  //this charge will be integrated in TDC mode
347  //disable for SARS ADC
348  busyFlags[jt] = true;
349 
350  const float extraCharge = chargeColl[jt];
351  if (extraCharge == 0.f)
352  continue;
353  if (debug)
354  edm::LogVerbatim("HGCFE") << "\t\t adding " << extraCharge << " fC @ deltaT=+" << (jt - it) << std::endl;
355 
356  totalCharge += extraCharge;
357  if (toaMode_ == WEIGHTEDBYE)
358  finalToA += extraCharge * toaColl[jt];
359  }
360 
361  //finalize ToA contamination
362  if (toaMode_ == WEIGHTEDBYE)
363  finalToA /= totalCharge;
364  }
365  newCharge[it] = (totalCharge - tdcOnset_fC_);
366 
367  if (debug)
368  edm::LogVerbatim("HGCFE") << "\t Final busy estimate=" << integTime << " ns = " << busyBxs << " bxs" << std::endl
369  << "\t Total integrated=" << totalCharge << " fC <toa>=" << toaFromToT[it]
370  << " (raw=" << finalToA << ") ns " << std::endl;
371 
372  //last fC (tdcOnset) are dissipated trough pulse
373  if (it + busyBxs < (int)(newCharge.size())) {
374  const float deltaT2nextBx((busyBxs * 25 - integTime));
375  const float tdcOnsetLeakage(tdcOnset_fC_ * vdt::fast_expf(-deltaT2nextBx / tdcChargeDrainParameterisation_[11]));
376  if (debug)
377  edm::LogVerbatim("HGCFE") << "\t Leaking remainder of TDC onset " << tdcOnset_fC_ << " fC, to be dissipated in "
378  << deltaT2nextBx << " DeltaT/tau=" << deltaT2nextBx << " / "
379  << tdcChargeDrainParameterisation_[11] << " ns, adds " << tdcOnsetLeakage << " fC @ "
380  << it + busyBxs << " bx (first free bx)" << std::endl;
381  newCharge[it + busyBxs] += tdcOnsetLeakage;
382  }
383  }
384 
385  //including the leakage from bunches in SARS ADC when not declared busy or in ToT
386  auto runChargeSharing = [&]() {
387  int ipulse = 0;
388  for (int it = 0; it < (int)(chargeColl.size()); ++it) {
389  //if busy, charge has been already integrated
390  //if(debug) edm::LogVerbatim("HGCFE") << "\t SARS ADC pulse activated @ " << it << " : ";
391  if (!totFlags[it] & !busyFlags[it]) {
392  const int start = std::max(0, 2 - it);
393  const int stop = std::min((int)adcPulse.size(), (int)newCharge.size() - it + 2);
394  for (ipulse = start; ipulse < stop; ++ipulse) {
395  const int itoffset = it + ipulse - 2;
396  //notice that if the channel is already busy,
397  //it has already been affected by the leakage of the SARS ADC
398  //if(totFlags[itoffset] || busyFlags[itoffset]) continue;
399  if (!totFlags[itoffset] & !busyFlags[itoffset]) {
400  newCharge[itoffset] += chargeColl[it] * adcPulse[ipulse];
401  }
402  //if(debug) edm::LogVerbatim("HGCFE") << " | " << itoffset << " " << chargeColl[it]*adcPulse[ipulse] << "( " << chargeColl[it] << "->";
403  //if(debug) edm::LogVerbatim("HGCFE") << newCharge[itoffset] << ") ";
404  }
405  }
406 
407  if (debug)
408  edm::LogVerbatim("HGCFE") << std::endl;
409  }
410  };
411  runChargeSharing();
412 
413  //For the future need to understand how to deal with toa for out of time signals
414  //and for that should keep track of the BX firing the ToA somewhere (also to restore the use of finalToA)
415  /*
416  float finalToA(0.);
417  for(int it=0; it<(int)(newCharge.size()); it++){
418  if(toaFlags[it]){
419  finalToA = toaFromToT[it];
420  //to avoid +=25 for small negative time taken as 0
421  while(finalToA < -1.e-5) finalToA+=25.f;
422  while(finalToA > 25.f) finalToA-=25.f;
423  toaFromToT[it] = finalToA;
424  }
425  }
426  */
427  //timeToA is already in 0-25ns range by construction
428 
429  //set new ADCs and ToA
430  if (debug)
431  edm::LogVerbatim("HGCFE") << "\t final result : ";
432  if (lsbADC < 0)
433  lsbADC = adcLSB_fC_;
434  if (maxADC < 0)
435  maxADC = adcSaturation_fC_;
436  for (int it = 0; it < (int)(newCharge.size()); it++) {
437  if (debug)
438  edm::LogVerbatim("HGCFE") << chargeColl[it] << " -> " << newCharge[it] << " ";
439 
440  HGCSample newSample;
441  if (totFlags[it] || busyFlags[it]) {
442  if (totFlags[it]) {
443  //brute force saturation, maybe could to better with an exponential like saturation
444  const float saturatedCharge(std::min(newCharge[it], tdcSaturation_fC_));
445  //working version for in-time PU and signal
446  newSample.set(
447  true, true, gainIdx, (uint16_t)(timeToA / toaLSB_ns_), (uint16_t)(std::floor(saturatedCharge / tdcLSB_fC_)));
448  if (toaFlags[it])
449  newSample.setToAValid(true);
450  } else {
451  newSample.set(false, true, gainIdx, 0, 0);
452  }
453  } else {
454  //brute force saturation, maybe could to better with an exponential like saturation
455  const uint16_t adc = std::floor(std::min(newCharge[it], maxADC) / lsbADC);
456  //working version for in-time PU and signal
457  newSample.set(adc > thrADC, false, gainIdx, (uint16_t)(timeToA / toaLSB_ns_), adc);
458  if (toaFlags[it])
459  newSample.setToAValid(true);
460  }
461  dataFrame.setSample(it, newSample);
462  }
463 
464  if (debug) {
465  std::ostringstream msg;
466  dataFrame.print(msg);
467  edm::LogVerbatim("HGCFE") << msg.str() << std::endl;
468  }
469 }

References gpuClustering::adc, hgcROCParameters_cfi::adcPulse, ALCARECOTkAlJpsiMuMu_cff::charge, debug, MillePedeFileConverter_cfg::e, f, myMath::fast_expf(), createfilelist::int, SiStripPI::max, min(), mps_check::msg, HGCSample::set(), HGCSample::setToAValid(), and Calorimetry_cff::thickness.

Referenced by HGCFEElectronics< DFr >::runShaper(), and HGCFEElectronics< DFr >::runShaperWithToT().

◆ runSimpleShaper() [1/2]

template<class DFr >
void HGCFEElectronics< DFr >::runSimpleShaper ( DFr &  dataFrame,
hgc::HGCSimHitData chargeColl,
uint32_t  thrADC,
float  lsbADC,
uint32_t  gainIdx,
float  maxADC 
)
inline

Definition at line 113 of file HGCFEElectronics.h.

114  {
115  runSimpleShaper(dataFrame, chargeColl, thrADC, lsbADC, gainIdx, maxADC, adcPulse_);
116  }

References HGCFEElectronics< DFr >::adcPulse_, and HGCFEElectronics< DFr >::runSimpleShaper().

◆ runSimpleShaper() [2/2]

template<class DFr >
void HGCFEElectronics< DFr >::runSimpleShaper ( DFr &  dataFrame,
hgc::HGCSimHitData chargeColl,
uint32_t  thrADC,
float  lsbADC,
uint32_t  gainIdx,
float  maxADC,
const hgc_digi::FEADCPulseShape adcPulse 
)

applies a shape to each time sample and propagates the tails to the subsequent time samples

Definition at line 149 of file HGCFEElectronics.cc.

155  {
156  //convolute with pulse shape to compute new ADCs
157  newCharge.fill(0.f);
158  bool debug(false);
159  for (int it = 0; it < (int)(chargeColl.size()); it++) {
160  const float charge(chargeColl[it]);
161  if (charge == 0.f)
162  continue;
163 
164 #ifdef EDM_ML_DEBUG
166 #endif
167 
168  if (debug)
169  edm::LogVerbatim("HGCFE") << "\t Redistributing SARS ADC" << charge << " @ " << it;
170 
171  for (int ipulse = -2; ipulse < (int)(adcPulse.size()) - 2; ipulse++) {
172  if (it + ipulse < 0)
173  continue;
174  if (it + ipulse >= (int)(dataFrame.size()))
175  continue;
176  const float chargeLeak = charge * adcPulse[(ipulse + 2)];
177  newCharge[it + ipulse] += chargeLeak;
178 
179  if (debug)
180  edm::LogVerbatim("HGCFE") << " | " << it + ipulse << " " << chargeLeak;
181  }
182 
183  if (debug)
184  edm::LogVerbatim("HGCFE") << std::endl;
185  }
186 
187  for (int it = 0; it < (int)(newCharge.size()); it++) {
188  //brute force saturation, maybe could to better with an exponential like saturation
189  const uint32_t adc = std::floor(std::min(newCharge[it], maxADC) / lsbADC);
190  HGCSample newSample;
191  newSample.set(adc > thrADC, false, gainIdx, 0, adc);
192  dataFrame.setSample(it, newSample);
193 
194  if (debug)
195  edm::LogVerbatim("HGCFE") << adc << " (" << std::min(newCharge[it], maxADC) << "/" << lsbADC << " ) ";
196  }
197 
198  if (debug) {
199  std::ostringstream msg;
200  dataFrame.print(msg);
201  edm::LogVerbatim("HGCFE") << msg.str() << std::endl;
202  }
203 }

References gpuClustering::adc, hgcROCParameters_cfi::adcPulse, ALCARECOTkAlJpsiMuMu_cff::charge, debug, f, createfilelist::int, min(), mps_check::msg, and HGCSample::set().

Referenced by HGCFEElectronics< DFr >::runShaper(), and HGCFEElectronics< DFr >::runSimpleShaper().

◆ runTrivialShaper()

template<class DFr >
void HGCFEElectronics< DFr >::runTrivialShaper ( DFr &  dataFrame,
hgc::HGCSimHitData chargeColl,
uint32_t  thrADC,
float  lsbADC,
uint32_t  gainIdx,
float  maxADC 
)

converts charge to digis without pulse shape

Definition at line 110 of file HGCFEElectronics.cc.

111  {
112  bool debug(false);
113 
114 #ifdef EDM_ML_DEBUG
115  for (int it = 0; it < (int)(chargeColl.size()); it++)
116  debug |= (chargeColl[it] > adcThreshold_fC_);
117 #endif
118 
119  if (debug)
120  edm::LogVerbatim("HGCFE") << "[runTrivialShaper]" << std::endl;
121 
122  if (lsbADC < 0)
123  lsbADC = adcLSB_fC_;
124  if (maxADC < 0)
125  // lower adcSaturation_fC_ by one part in a million
126  // to ensure largest charge converted in bits is 0xfff==4095, not 0x1000
127  // no effect on charges loewer than; no impact on cpu time, only done once
128  maxADC = adcSaturation_fC_ * (1 - 1e-6);
129  for (int it = 0; it < (int)(chargeColl.size()); it++) {
130  //brute force saturation, maybe could to better with an exponential like saturation
131  const uint32_t adc = std::floor(std::min(chargeColl[it], maxADC) / lsbADC);
132  HGCSample newSample;
133  newSample.set(adc > thrADC, false, gainIdx, 0, adc);
134  dataFrame.setSample(it, newSample);
135 
136  if (debug)
137  edm::LogVerbatim("HGCFE") << adc << " (" << chargeColl[it] << "/" << adcLSB_fC_ << ") ";
138  }
139 
140  if (debug) {
141  std::ostringstream msg;
142  dataFrame.print(msg);
143  edm::LogVerbatim("HGCFE") << msg.str() << std::endl;
144  }
145 }

References gpuClustering::adc, debug, MillePedeFileConverter_cfg::e, createfilelist::int, min(), mps_check::msg, and HGCSample::set().

Referenced by HGCFEElectronics< DFr >::runShaper().

◆ setADClsb()

template<class DFr >
void HGCFEElectronics< DFr >::setADClsb ( float  newLSB)
inline

Definition at line 95 of file HGCFEElectronics.h.

95 { adcLSB_fC_ = newLSB; }

References HGCFEElectronics< DFr >::adcLSB_fC_.

◆ SetNoiseValues()

template<class DFr >
void HGCFEElectronics< DFr >::SetNoiseValues ( const std::vector< float > &  noise_fC)
inline

Definition at line 74 of file HGCFEElectronics.h.

74  {
75  noise_fC_.insert(noise_fC_.end(), noise_fC.begin(), noise_fC.end());
76  };

References hgcalDigitizer_cfi::noise_fC, and HGCFEElectronics< DFr >::noise_fC_.

◆ toaMode()

template<class DFr >
uint32_t HGCFEElectronics< DFr >::toaMode ( ) const
inline

returns how ToT will be computed

Definition at line 146 of file HGCFEElectronics.h.

146 { return toaMode_; }

References HGCFEElectronics< DFr >::toaMode_.

Member Data Documentation

◆ adcLSB_fC_

template<class DFr >
float HGCFEElectronics< DFr >::adcLSB_fC_
private

◆ adcPulse_

template<class DFr >
hgc_digi::FEADCPulseShape HGCFEElectronics< DFr >::adcPulse_
private

◆ adcSaturation_fC_

template<class DFr >
float HGCFEElectronics< DFr >::adcSaturation_fC_
private

Definition at line 164 of file HGCFEElectronics.h.

◆ adcThreshold_fC_

template<class DFr >
float HGCFEElectronics< DFr >::adcThreshold_fC_
private

Definition at line 164 of file HGCFEElectronics.h.

Referenced by HGCFEElectronics< DFr >::getADCThreshold().

◆ busyFlags

template<class DFr >
std::array<bool, hgc::nSamples> HGCFEElectronics< DFr >::busyFlags
private

Definition at line 172 of file HGCFEElectronics.h.

◆ fwVersion_

template<class DFr >
uint32_t HGCFEElectronics< DFr >::fwVersion_
private

Definition at line 160 of file HGCFEElectronics.h.

Referenced by HGCFEElectronics< DFr >::runShaper().

◆ jitterConstant2_ns_

template<class DFr >
std::array<float, 3> HGCFEElectronics< DFr >::jitterConstant2_ns_
private

Definition at line 167 of file HGCFEElectronics.h.

Referenced by HGCFEElectronics< DFr >::getTimeJitter().

◆ jitterNoise2_ns_

template<class DFr >
std::array<float, 3> HGCFEElectronics< DFr >::jitterNoise2_ns_
private

Definition at line 167 of file HGCFEElectronics.h.

Referenced by HGCFEElectronics< DFr >::getTimeJitter().

◆ newCharge

template<class DFr >
hgc::HGCSimHitData HGCFEElectronics< DFr >::newCharge
private

Definition at line 173 of file HGCFEElectronics.h.

◆ noise_fC_

template<class DFr >
std::vector<float> HGCFEElectronics< DFr >::noise_fC_
private

◆ pulseAvgT_

template<class DFr >
hgc_digi::FEADCPulseShape HGCFEElectronics< DFr >::pulseAvgT_
private

Definition at line 161 of file HGCFEElectronics.h.

◆ targetMIPvalue_ADC_

template<class DFr >
uint32_t HGCFEElectronics< DFr >::targetMIPvalue_ADC_
private

Definition at line 166 of file HGCFEElectronics.h.

Referenced by HGCFEElectronics< DFr >::getTargetMipValue().

◆ tdcChargeDrainParameterisation_

template<class DFr >
std::vector<float> HGCFEElectronics< DFr >::tdcChargeDrainParameterisation_
private

Definition at line 163 of file HGCFEElectronics.h.

◆ tdcForToAOnset_fC_

template<class DFr >
std::array<float, 3> HGCFEElectronics< DFr >::tdcForToAOnset_fC_
private

Definition at line 162 of file HGCFEElectronics.h.

Referenced by HGCFEElectronics< DFr >::getTDCForToAOnset().

◆ tdcLSB_fC_

template<class DFr >
float HGCFEElectronics< DFr >::tdcLSB_fC_
private

Definition at line 164 of file HGCFEElectronics.h.

Referenced by HGCFEElectronics< DFr >::getTDClsb().

◆ tdcOnset_fC_

template<class DFr >
float HGCFEElectronics< DFr >::tdcOnset_fC_
private

Definition at line 164 of file HGCFEElectronics.h.

Referenced by HGCFEElectronics< DFr >::getTDCOnset().

◆ tdcResolutionInNs_

template<class DFr >
float HGCFEElectronics< DFr >::tdcResolutionInNs_
private

Definition at line 164 of file HGCFEElectronics.h.

◆ tdcSaturation_fC_

template<class DFr >
float HGCFEElectronics< DFr >::tdcSaturation_fC_
private

Definition at line 164 of file HGCFEElectronics.h.

◆ thresholdFollowsMIP_

template<class DFr >
bool HGCFEElectronics< DFr >::thresholdFollowsMIP_
private

Definition at line 170 of file HGCFEElectronics.h.

◆ toaFlags

template<class DFr >
std::array<bool, hgc::nSamples> HGCFEElectronics< DFr >::toaFlags
private

Definition at line 172 of file HGCFEElectronics.h.

◆ toaFromToT

template<class DFr >
hgc::HGCSimHitData HGCFEElectronics< DFr >::toaFromToT
private

Definition at line 173 of file HGCFEElectronics.h.

◆ toaLSB_ns_

template<class DFr >
float HGCFEElectronics< DFr >::toaLSB_ns_
private

Definition at line 164 of file HGCFEElectronics.h.

◆ toaMode_

template<class DFr >
uint32_t HGCFEElectronics< DFr >::toaMode_
private

Definition at line 169 of file HGCFEElectronics.h.

Referenced by HGCFEElectronics< DFr >::toaMode().

◆ totFlags

template<class DFr >
std::array<bool, hgc::nSamples> HGCFEElectronics< DFr >::totFlags
private

Definition at line 172 of file HGCFEElectronics.h.

mps_fire.i
i
Definition: mps_fire.py:428
start
Definition: start.py:1
dqmMemoryStats.float
float
Definition: dqmMemoryStats.py:127
HGCFEElectronics::adcSaturation_fC_
float adcSaturation_fC_
Definition: HGCFEElectronics.h:164
HGCFEElectronics::jitterNoise2_ns_
std::array< float, 3 > jitterNoise2_ns_
Definition: HGCFEElectronics.h:167
HGCFEElectronics::toaFromToT
hgc::HGCSimHitData toaFromToT
Definition: HGCFEElectronics.h:173
f
double f[11][100]
Definition: MuScleFitUtils.cc:78
HGCFEElectronics::tdcChargeDrainParameterisation_
std::vector< float > tdcChargeDrainParameterisation_
Definition: HGCFEElectronics.h:163
min
T min(T a, T b)
Definition: MathUtil.h:58
gpuClustering::adc
uint16_t *__restrict__ uint16_t const *__restrict__ adc
Definition: gpuClusterChargeCut.h:20
HGCFEElectronics::WITHTOT
Definition: HGCFEElectronics.h:26
HGCSample::set
void set(bool thr, bool mode, uint16_t gain, uint16_t toa, uint16_t data)
Definition: HGCSample.h:49
HGCFEElectronics::totFlags
std::array< bool, hgc::nSamples > totFlags
Definition: HGCFEElectronics.h:172
HGCFEElectronics::runShaper
void runShaper(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, hgc::HGCSimHitData &toa, const hgc_digi::FEADCPulseShape &adcPulse, CLHEP::HepRandomEngine *engine, uint32_t thrADC=0, float lsbADC=-1, uint32_t gainIdx=0, float maxADC=-1, int thickness=1)
switches according to the firmware version
Definition: HGCFEElectronics.h:37
HGCFEElectronics::toaLSB_ns_
float toaLSB_ns_
Definition: HGCFEElectronics.h:164
HGCFEElectronics::tdcResolutionInNs_
float tdcResolutionInNs_
Definition: HGCFEElectronics.h:164
mps_check.msg
tuple msg
Definition: mps_check.py:285
HGCFEElectronics::TRIVIAL
Definition: HGCFEElectronics.h:26
HGCFEElectronics::toaFlags
std::array< bool, hgc::nSamples > toaFlags
Definition: HGCFEElectronics.h:172
HGCFEElectronics::runSimpleShaper
void runSimpleShaper(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC, const hgc_digi::FEADCPulseShape &adcPulse)
applies a shape to each time sample and propagates the tails to the subsequent time samples
Definition: HGCFEElectronics.cc:149
groupFilesInBlocks.temp
list temp
Definition: groupFilesInBlocks.py:142
HGCFEElectronics::SIMPLE
Definition: HGCFEElectronics.h:26
HGCFEElectronics::tdcOnset_fC_
float tdcOnset_fC_
Definition: HGCFEElectronics.h:164
HGCFEElectronics::WEIGHTEDBYE
Definition: HGCFEElectronics.h:27
HGCFEElectronics::getTimeJitter
float getTimeJitter(float totalCharge, int thickness)
Definition: HGCFEElectronics.h:78
HGCSample::setToAValid
void setToAValid(bool toaFired)
Definition: HGCSample.h:47
debug
#define debug
Definition: HDRShower.cc:19
myMath::fast_expf
float fast_expf(float x)
Definition: EcalUncalibRecHitRatioMethodAlgo.h:27
Calorimetry_cff.thickness
thickness
Definition: Calorimetry_cff.py:115
HGCFEElectronics::toaMode_
uint32_t toaMode_
Definition: HGCFEElectronics.h:169
HGCFEElectronics::runTrivialShaper
void runTrivialShaper(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC)
converts charge to digis without pulse shape
Definition: HGCFEElectronics.cc:110
mathSSE::sqrt
T sqrt(T t)
Definition: SSEVec.h:19
hgcROCParameters_cfi.adcPulse
adcPulse
Definition: hgcROCParameters_cfi.py:10
HGCSample
wrapper for a data word
Definition: HGCSample.h:13
HGCFEElectronics::SIMPLETHRESHOLD
Definition: HGCFEElectronics.h:27
ALCARECOTkAlJpsiMuMu_cff.charge
charge
Definition: ALCARECOTkAlJpsiMuMu_cff.py:47
edm::ParameterSet::exists
bool exists(std::string const &parameterName) const
checks if a parameter exists
Definition: ParameterSet.cc:681
HGCFEElectronics::adcLSB_fC_
float adcLSB_fC_
Definition: HGCFEElectronics.h:164
hgcalDigitizer_cfi.noise_fC
noise_fC
Definition: hgcalDigitizer_cfi.py:96
SiStripPI::max
Definition: SiStripPayloadInspectorHelper.h:169
HLTEgPhaseIITestSequence_cff.adcNbits
adcNbits
Definition: HLTEgPhaseIITestSequence_cff.py:945
createfilelist.int
int
Definition: createfilelist.py:10
HGCFEElectronics::runShaperWithToT
void runShaperWithToT(DFr &dataFrame, hgc::HGCSimHitData &chargeColl, hgc::HGCSimHitData &toa, CLHEP::HepRandomEngine *engine, uint32_t thrADC, float lsbADC, uint32_t gainIdx, float maxADC, int thickness, const hgc_digi::FEADCPulseShape &adcPulse)
implements pulse shape and switch to time over threshold including deadtime
Definition: HGCFEElectronics.cc:207
HGCFEElectronics::noise_fC_
std::vector< float > noise_fC_
Definition: HGCFEElectronics.h:168
HGCFEElectronics::newCharge
hgc::HGCSimHitData newCharge
Definition: HGCFEElectronics.h:173
HGCFEElectronics::jitterConstant2_ns_
std::array< float, 3 > jitterConstant2_ns_
Definition: HGCFEElectronics.h:167
HGCFEElectronics::pulseAvgT_
hgc_digi::FEADCPulseShape pulseAvgT_
Definition: HGCFEElectronics.h:161
HGCFEElectronics::targetMIPvalue_ADC_
uint32_t targetMIPvalue_ADC_
Definition: HGCFEElectronics.h:166
HGCFEElectronics::tdcLSB_fC_
float tdcLSB_fC_
Definition: HGCFEElectronics.h:164
heppy_batch.val
val
Definition: heppy_batch.py:351
HGCFEElectronics::tdcForToAOnset_fC_
std::array< float, 3 > tdcForToAOnset_fC_
Definition: HGCFEElectronics.h:162
HGCFEElectronics::adcThreshold_fC_
float adcThreshold_fC_
Definition: HGCFEElectronics.h:164
edm::LogVerbatim
Log< level::Info, true > LogVerbatim
Definition: MessageLogger.h:128
Exception
Definition: hltDiff.cc:245
HGCFEElectronics::tdcSaturation_fC_
float tdcSaturation_fC_
Definition: HGCFEElectronics.h:164
edm::ParameterSet::getParameter
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
HLTEgPhaseIITestSequence_cff.tdcNbits
tdcNbits
Definition: HLTEgPhaseIITestSequence_cff.py:949
funct::pow
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
HGCFEElectronics::fwVersion_
uint32_t fwVersion_
Definition: HGCFEElectronics.h:160
HGCFEElectronics::busyFlags
std::array< bool, hgc::nSamples > busyFlags
Definition: HGCFEElectronics.h:172
HGCFEElectronics::adcPulse_
hgc_digi::FEADCPulseShape adcPulse_
Definition: HGCFEElectronics.h:161
MillePedeFileConverter_cfg.e
e
Definition: MillePedeFileConverter_cfg.py:37