CMS 3D CMS Logo

HGCHEbackDigitizer.cc
Go to the documentation of this file.
2 
3 #include "CLHEP/Random/RandPoissonQ.h"
4 #include "CLHEP/Random/RandGaussQ.h"
5 
8 
9 #include "vdt/vdtMath.h"
10 
11 using namespace hgc_digi;
12 using namespace hgc_digi_utils;
13 
14 //
17  algo_ = cfg.getParameter<uint32_t>("algo");
18  scaleByTileArea_ = cfg.getParameter<bool>("scaleByTileArea");
19  scaleBySipmArea_ = cfg.getParameter<bool>("scaleBySipmArea");
20  sipmMapFile_ = cfg.getParameter<std::string>("sipmMap");
21  scaleByDose_ = cfg.getParameter<edm::ParameterSet>("noise").getParameter<bool>("scaleByDose");
22  unsigned int scaleByDoseAlgo = cfg.getParameter<edm::ParameterSet>("noise").getParameter<uint32_t>("scaleByDoseAlgo");
23  doseMapFile_ = cfg.getParameter<edm::ParameterSet>("noise").getParameter<std::string>("doseMap");
24  noise_MIP_ = cfg.getParameter<edm::ParameterSet>("noise").getParameter<double>("noise_MIP");
25  thresholdFollowsMIP_ = cfg.getParameter<bool>("thresholdFollowsMIP");
26  keV2MIP_ = cfg.getParameter<double>("keV2MIP");
27  this->keV2fC_ = 1.0; //keV2MIP_; // hack for HEB
28  nPEperMIP_ = cfg.getParameter<double>("nPEperMIP");
29  nTotalPE_ = cfg.getParameter<double>("nTotalPE");
30  xTalk_ = cfg.getParameter<double>("xTalk");
31  sdPixels_ = cfg.getParameter<double>("sdPixels");
32 
33  scal_.setDoseMap(doseMapFile_, scaleByDoseAlgo);
34  scal_.setSipmMap(sipmMapFile_);
35 }
36 
37 //
38 void HGCHEbackDigitizer::runDigitizer(std::unique_ptr<HGCalDigiCollection>& digiColl,
39  HGCSimHitDataAccumulator& simData,
40  const CaloSubdetectorGeometry* theGeom,
41  const std::unordered_set<DetId>& validIds,
42  uint32_t digitizationType,
43  CLHEP::HepRandomEngine* engine) {
44  if (algo_ == 0)
45  runEmptyDigitizer(digiColl, simData, theGeom, validIds, engine);
46  else if (algo_ == 1)
47  runCaliceLikeDigitizer(digiColl, simData, theGeom, validIds, engine);
48  else if (algo_ == 2)
49  runRealisticDigitizer(digiColl, simData, theGeom, validIds, engine);
50 }
51 
52 void HGCHEbackDigitizer::runEmptyDigitizer(std::unique_ptr<HGCalDigiCollection>& digiColl,
53  HGCSimHitDataAccumulator& simData,
54  const CaloSubdetectorGeometry* theGeom,
55  const std::unordered_set<DetId>& validIds,
56  CLHEP::HepRandomEngine* engine) {
57  HGCSimHitData chargeColl, toa;
58  // this represents a cell with no signal charge
59  HGCCellInfo zeroData;
60  zeroData.hit_info[0].fill(0.f); //accumulated energy
61  zeroData.hit_info[1].fill(0.f); //time-of-flight
62 
63  for (const auto& id : validIds) {
64  chargeColl.fill(0.f);
65  toa.fill(0.f);
66  HGCSimHitDataAccumulator::iterator it = simData.find(id);
67  HGCCellInfo& cell = (simData.end() == it ? zeroData : it->second);
68  addCellMetadata(cell, theGeom, id);
69 
70  for (size_t i = 0; i < cell.hit_info[0].size(); ++i) {
71  //convert total energy keV->MIP, since converted to keV in accumulator
72  const float totalIniMIPs(cell.hit_info[0][i] * keV2MIP_);
73 
74  //store
75  chargeColl[i] = totalIniMIPs;
76  }
77 
78  //init a new data frame and run shaper
79  HGCalDataFrame newDataFrame(id);
80  this->myFEelectronics_->runShaper(newDataFrame, chargeColl, toa, engine);
81 
82  //prepare the output
83  this->updateOutput(digiColl, newDataFrame);
84  }
85 }
86 
87 void HGCHEbackDigitizer::runRealisticDigitizer(std::unique_ptr<HGCalDigiCollection>& digiColl,
88  HGCSimHitDataAccumulator& simData,
89  const CaloSubdetectorGeometry* theGeom,
90  const std::unordered_set<DetId>& validIds,
91  CLHEP::HepRandomEngine* engine) {
92  //switch to true if you want to print some details
93  constexpr bool debug(false);
94 
95  HGCSimHitData chargeColl, toa;
96  // this represents a cell with no signal charge
97  HGCCellInfo zeroData;
98  zeroData.hit_info[0].fill(0.f); //accumulated energy
99  zeroData.hit_info[1].fill(0.f); //time-of-flight
100 
101  // needed to compute the radiation and geometry scale factors
102  scal_.setGeometry(theGeom);
103 
104  for (const auto& id : validIds) {
105  chargeColl.fill(0.f);
106  toa.fill(0.f);
107  HGCSimHitDataAccumulator::iterator it = simData.find(id);
108  HGCCellInfo& cell = (simData.end() == it ? zeroData : it->second);
109  addCellMetadata(cell, theGeom, id);
110 
111  float scaledPePerMip = nPEperMIP_; //needed to scale according to tile geometry
112  float tunedNoise = nPEperMIP_ * noise_MIP_; //flat noise case
113  float sipmFactor = 1.; //standard 2 mm^2 sipm
114 
115  if (id.det() == DetId::HGCalHSc) //skip those geometries that have HE used as BH
116  {
119  radius = scal_.computeRadius(id);
120 
121  //take into account the tile size
122  if (scaleByTileArea_)
123  scaledPePerMip *= scal_.scaleByTileArea(id, radius);
124 
125  //take into account the darkening of the scintillator and SiPM dark current
126  if (scaleByDose_) {
127  auto dosePair = scal_.scaleByDose(id, radius);
128  scaledPePerMip *= dosePair.first;
129  tunedNoise = dosePair.second;
130  }
131 
132  //take into account the sipm size
133  if (scaleBySipmArea_) {
134  sipmFactor = scal_.scaleBySipmArea(id, radius[0]);
135  scaledPePerMip *= sipmFactor;
136  tunedNoise *= sqrt(sipmFactor);
137  }
138  }
139 
140  //set mean for poissonian noise
141  float meanN = std::pow(tunedNoise, 2);
142 
143  for (size_t i = 0; i < cell.hit_info[0].size(); ++i) {
144  //convert total energy keV->MIP, since converted to keV in accumulator
145  float totalIniMIPs(cell.hit_info[0][i] * keV2MIP_);
146 
147  //generate the number of photo-electrons from the energy deposit
148  const uint32_t npeS = std::floor(CLHEP::RandPoissonQ::shoot(engine, totalIniMIPs * scaledPePerMip) + 0.5);
149 
150  //generate the noise associated to the dark current
151  const uint32_t npeN = std::floor(CLHEP::RandPoissonQ::shoot(engine, meanN) + 0.5);
152 
153  //total number of pe from signal + noise (not subtracting pedestal)
154  const uint32_t npe = npeS + npeN;
155 
156  //take into account SiPM saturation
157  float nTotalPixels = nTotalPE_ * sipmFactor;
158  const float x = vdt::fast_expf(-((float)npe) / nTotalPixels);
159  uint32_t nPixel(0);
160  if (xTalk_ * x != 1)
161  nPixel = (uint32_t)std::max(nTotalPixels * (1.f - x) / (1.f - xTalk_ * x), 0.f);
162 
163  //take into account the gain fluctuations of each pixel
164  //const float nPixelTot = nPixel + sqrt(nPixel) * CLHEP::RandGaussQ::shoot(engine, 0., 0.05); //FDG: just a note for now, par to be defined
165 
166  //scale to calibrated response depending on the thresholdFollowsMIP_ flag
167  float totalMIPs = thresholdFollowsMIP_ ? std::max((npe - meanN), 0.f) / nPEperMIP_ : nPixel / nPEperMIP_;
168 
169  if (debug && totalIniMIPs > 0) {
170  LogDebug("HGCHEbackDigitizer") << "npeS: " << npeS << " npeN: " << npeN << " npe: " << npe
171  << " meanN: " << meanN << " noise_MIP_: " << noise_MIP_
172  << " nPEperMIP_: " << nPEperMIP_ << " scaledPePerMip: " << scaledPePerMip
173  << " nPixel: " << nPixel;
174  LogDebug("HGCHEbackDigitizer") << "totalIniMIPs: " << totalIniMIPs << " totalMIPs: " << totalMIPs << std::endl;
175  }
176 
177  //store charge
178  chargeColl[i] = totalMIPs;
179 
180  //update time of arrival
181  toa[i] = cell.hit_info[1][i];
182  if (myFEelectronics_->toaMode() == HGCFEElectronics<HGCalDataFrame>::WEIGHTEDBYE && totalIniMIPs > 0)
183  toa[i] = cell.hit_info[1][i] / totalIniMIPs;
184  }
185 
186  //init a new data frame and run shaper
187  HGCalDataFrame newDataFrame(id);
188  float adcThr = this->myFEelectronics_->getADCThreshold(); //this is in MIPs
189  float adcLsb = this->myFEelectronics_->getADClsb();
190  uint32_t thrADC(thresholdFollowsMIP_ ? std::floor(adcThr / adcLsb * scaledPePerMip / nPEperMIP_)
191  : std::floor(adcThr / adcLsb));
192 
193  this->myFEelectronics_->runShaper(newDataFrame, chargeColl, toa, engine, thrADC);
194 
195  //prepare the output
196  this->updateOutput(digiColl, newDataFrame);
197  }
198 }
199 
200 //
201 void HGCHEbackDigitizer::runCaliceLikeDigitizer(std::unique_ptr<HGCalDigiCollection>& digiColl,
202  HGCSimHitDataAccumulator& simData,
203  const CaloSubdetectorGeometry* theGeom,
204  const std::unordered_set<DetId>& validIds,
205  CLHEP::HepRandomEngine* engine) {
206  //switch to true if you want to print some details
207  constexpr bool debug(false);
208 
209  HGCSimHitData chargeColl, toa;
210 
211  // this represents a cell with no signal charge
212  HGCCellInfo zeroData;
213  zeroData.hit_info[0].fill(0.f); //accumulated energy
214  zeroData.hit_info[1].fill(0.f); //time-of-flight
215 
216  for (const auto& id : validIds) {
217  chargeColl.fill(0.f);
218  HGCSimHitDataAccumulator::iterator it = simData.find(id);
219  HGCCellInfo& cell = (simData.end() == it ? zeroData : it->second);
220  addCellMetadata(cell, theGeom, id);
221 
222  for (size_t i = 0; i < cell.hit_info[0].size(); ++i) {
223  //convert total energy keV->MIP, since converted to keV in accumulator
224  const float totalIniMIPs(cell.hit_info[0][i] * keV2MIP_);
225 
226  //generate random number of photon electrons
227  const uint32_t npe = std::floor(CLHEP::RandPoissonQ::shoot(engine, totalIniMIPs * nPEperMIP_));
228 
229  //number of pixels
230  const float x = vdt::fast_expf(-((float)npe) / nTotalPE_);
231  uint32_t nPixel(0);
232  if (xTalk_ * x != 1)
233  nPixel = (uint32_t)std::max(nTotalPE_ * (1.f - x) / (1.f - xTalk_ * x), 0.f);
234 
235  //update signal
236  if (sdPixels_ != 0)
237  nPixel = (uint32_t)std::max(CLHEP::RandGaussQ::shoot(engine, (double)nPixel, sdPixels_), 0.);
238 
239  //convert to MIP again and saturate
240  float totalMIPs(0.f), xtalk = 0.f;
241  const float peDiff = nTotalPE_ - (float)nPixel;
242  if (peDiff != 0.f) {
243  xtalk = (nTotalPE_ - xTalk_ * ((float)nPixel)) / peDiff;
244  if (xtalk > 0.f && nPEperMIP_ != 0.f)
245  totalMIPs = (nTotalPE_ / nPEperMIP_) * vdt::fast_logf(xtalk);
246  }
247 
248  //add noise (in MIPs)
249  chargeColl[i] = totalMIPs;
250  if (noise_MIP_ != 0)
251  chargeColl[i] += std::max(CLHEP::RandGaussQ::shoot(engine, 0., noise_MIP_), 0.);
252  if (debug && cell.hit_info[0][i] > 0)
253  edm::LogVerbatim("HGCDigitizer") << "[runCaliceLikeDigitizer] xtalk=" << xtalk << " En=" << cell.hit_info[0][i]
254  << " keV -> " << totalIniMIPs << " raw-MIPs -> " << chargeColl[i]
255  << " digi-MIPs";
256  }
257 
258  //init a new data frame and run shaper
259  HGCalDataFrame newDataFrame(id);
260  this->myFEelectronics_->runShaper(newDataFrame, chargeColl, toa, engine);
261 
262  //prepare the output
263  this->updateOutput(digiColl, newDataFrame);
264  }
265 }
266 
267 //
#define LogDebug(id)
void runRealisticDigitizer(std::unique_ptr< HGCalDigiCollection > &digiColl, hgc::HGCSimHitDataAccumulator &simData, const CaloSubdetectorGeometry *theGeom, const std::unordered_set< DetId > &validIds, CLHEP::HepRandomEngine *engine)
T getParameter(std::string const &) const
std::array< double, 8 > radiiVec
void updateOutput(std::unique_ptr< DColl > &coll, const HGCalDataFrame &rawDataFrame)
prepares the output according to the number of time samples to produce
void runEmptyDigitizer(std::unique_ptr< HGCalDigiCollection > &digiColl, hgc::HGCSimHitDataAccumulator &simData, const CaloSubdetectorGeometry *theGeom, const std::unordered_set< DetId > &validIds, CLHEP::HepRandomEngine *engine)
void setSipmMap(const std::string &)
void setGeometry(const CaloSubdetectorGeometry *)
std::unordered_map< uint32_t, HGCCellInfo > HGCSimHitDataAccumulator
void addCellMetadata(HGCCellInfo &info, const HcalGeometry *geom, const DetId &detid)
HGCalSciNoiseMap scal_
radiiVec computeRadius(const HGCScintillatorDetId &)
std::array< HGCSimData_t, nSamples > HGCSimHitData
HGCHEbackDigitizer(const edm::ParameterSet &ps)
double scaleByTileArea(const HGCScintillatorDetId &, const radiiVec &)
returns the signal scaling and the noise
double scaleBySipmArea(const HGCScintillatorDetId &, const double &)
T sqrt(T t)
Definition: SSEVec.h:19
std::array< HGCSimHitData, 2 > hit_info
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
std::unique_ptr< HGCFEElectronics< HGCalDataFrame > > myFEelectronics_
double f[11][100]
#define debug
Definition: HDRShower.cc:19
void setDoseMap(const std::string &, const unsigned int)
Readout digi for HGC.
Definition: HGCDataFrame.h:14
std::pair< double, double > scaleByDose(const HGCScintillatorDetId &, const radiiVec &)
void runCaliceLikeDigitizer(std::unique_ptr< HGCalDigiCollection > &digiColl, hgc::HGCSimHitDataAccumulator &simData, const CaloSubdetectorGeometry *theGeom, const std::unordered_set< DetId > &validIds, CLHEP::HepRandomEngine *engine)
float fast_expf(float x)
models the behavior of the front-end electronics
void runDigitizer(std::unique_ptr< HGCalDigiCollection > &digiColl, hgc::HGCSimHitDataAccumulator &simData, const CaloSubdetectorGeometry *theGeom, const std::unordered_set< DetId > &validIds, uint32_t digitizationType, CLHEP::HepRandomEngine *engine) override
to be specialized by top class
float fast_logf(float x)
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:30
#define constexpr