ATLAS Offline Software
Loading...
Searching...
No Matches
LArHitEMapToDigitAlg.cxx
Go to the documentation of this file.
1/*
2 * Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3 */
6#include "CLHEP/Random/RandGaussZiggurat.h"
14
16#include "CLHEP/Random/RandomEngine.h"
17#include <CLHEP/Random/Randomize.h>
18
20
21using CLHEP::RandFlat;
22using CLHEP::RandGaussZiggurat;
23
25{
26
28 ATH_MSG_ERROR("Requested Nsamples " << m_NSamples << " larger than max "
29 << s_MaxNSamples);
30 return StatusCode::FAILURE;
31 }
34
35 ATH_CHECK(m_shapeKey.initialize());
36 ATH_CHECK(m_fSamplKey.initialize());
37 ATH_CHECK(m_OFCKey.initialize());
38 ATH_CHECK(m_pedestalKey.initialize());
40 ATH_CHECK(m_bcContKey.initialize());
41 ATH_CHECK(m_badFebKey.initialize());
42 ATH_CHECK(m_adc2mevKey.initialize());
43 ATH_CHECK(m_caloMgrKey.initialize());
44
45 ATH_CHECK(m_cablingKey.initialize());
46
47 // helpers
48 //retrieve ID helpers
49 ATH_CHECK(detStore()->retrieve(m_calocell_id,"CaloCell_ID"));
50
51
52 const CaloIdManager* caloIdMgr = nullptr;
53 StatusCode sc = detStore()->retrieve(caloIdMgr);
54 if (sc.isFailure()) {
55 ATH_MSG_ERROR(" Unable to retrieve CaloIdManager from DetectoreStore");
56 return StatusCode::FAILURE;
57 }
58 m_larem_id = caloIdMgr->getEM_ID();
59 m_larhec_id = caloIdMgr->getHEC_ID();
60 m_larfcal_id = caloIdMgr->getFCAL_ID();
61
62 sc = detStore()->retrieve(m_laronline_id);
63 if (sc.isFailure()) {
64 ATH_MSG_ERROR(" Unable to retrieve LArOnlineId from DetectoreStore");
65 return StatusCode::FAILURE;
66 }
67 ATH_CHECK(m_bcMask.buildBitMask(m_problemsToMask,msg()));
68
69 // Services
70 ATH_CHECK(m_rndmGenSvc.retrieve());
71 ATH_CHECK(m_hitMapKey.initialize());
73
74 ATH_CHECK(m_DigitContainerName.initialize());
76
77 // Check consistency of gain-ranges and gain-switching thresholds:
78 std::array<std::pair<int,std::string>,4> iCaloToStr{{{EM,"EM"},{HEC,"HEC"},{FCAL,"FCAL"},{EMIW,"EMIW"}}};
79
80 for (int iCalo = EM; iCalo <= EMIW; ++iCalo) {
81 if ((m_gainRange[iCalo].value().first == CaloGain::LARHIGHGAIN) == (m_HighGainThresh[iCalo] != 0))
82 ATH_MSG_INFO("jobO consistency check: " << iCaloToStr[iCalo] << " has " << ((m_gainRange[iCalo].value().first == CaloGain::LARHIGHGAIN) ? "" : "no ")
83 << " HIGH gain and high Gain threshold=" << m_HighGainThresh[iCalo]);
84 else {
85 ATH_MSG_ERROR("jobO inconsistency! " << iCaloToStr[iCalo] << " has" << ((m_gainRange[iCalo].value().first == CaloGain::LARHIGHGAIN) ? "" : "no ")
86 << " HIGH gain but high Gain threshold=" << m_HighGainThresh[iCalo]);
87 return StatusCode::FAILURE;
88 }
89 if ((m_gainRange[iCalo].value().second == CaloGain::LARLOWGAIN) == (m_LowGainThresh[iCalo] <= m_maxADC))
90 ATH_MSG_INFO("jobO consistency check: Calo " << iCaloToStr[iCalo] << " has" << ((m_gainRange[iCalo].value().first == CaloGain::LARHIGHGAIN) ? "" : "no ")
91 << " LOW gain and high Gain threshold=" << m_LowGainThresh[iCalo] << " (maxADC=" << m_maxADC << ")");
92 else {
93 ATH_MSG_ERROR("jobO inconsistency! Calo " << iCaloToStr[iCalo] << " has" << ((m_gainRange[iCalo].value().first == CaloGain::LARHIGHGAIN) ? "" : "no ")
94 << " LOW gain but high Gain threshold=" << m_LowGainThresh[iCalo] << " (maxADC=" << m_maxADC << ")");
95 return StatusCode::FAILURE;
96 }
97
98 if (m_gainRange[iCalo].value().first == m_gainRange[iCalo].value().second) {
99 ATH_MSG_ERROR(" Calo " << iCaloToStr[iCalo] << " configured to have only one gain. This is not supported.");
100 return Status::FAILURE;
101 }
102 if (m_HighGainThresh[iCalo] >= m_LowGainThresh[iCalo] ) {
103 ATH_MSG_ERROR(" Calo " << iCaloToStr[iCalo] << " High gain threshold > low gain threshold! " << m_HighGainThresh[iCalo] << " >= " << m_LowGainThresh[iCalo]);
104 return Status::FAILURE;
105 }
106
107
108 } //end iCalo loop
109
110 return StatusCode::SUCCESS;
111}
112
113
114StatusCode LArHitEMapToDigitAlg::execute(const EventContext& context) const {
115
116 // load many conditions
119 const LArOnOffIdMapping* cabling=*cablingHdl;
120 if(!cabling) {
121 ATH_MSG_ERROR("Failed to retrieve LAr Cabling map with key " << m_cablingKey.key() );
122 return StatusCode::FAILURE;
123 }
124
125 SG::ReadCondHandle<LArADC2MeV> adc2mevHdl(m_adc2mevKey, context);
126 const LArADC2MeV* adc2MeVs=*adc2mevHdl;
127
129 const ILArfSampl* fSampl=*fSamplHdl;
130
132 const ILArPedestal* pedestal=*pedHdl;
133
134 const ILArNoise* noise=nullptr;
136 SG::ReadCondHandle<ILArNoise> noiseHdl(m_noiseKey, context);
137 noise=*noiseHdl;
138 }
139
140 const LArAutoCorrNoise* autoCorrNoise=nullptr;
143 autoCorrNoise=*autoCorrNoiseHdl;
144 }
145
148 const LArBadChannelCont* bcCont{*bch};
149
150 SG::ReadCondHandle<ILArShape> shapeHdl(m_shapeKey, context);
151 const ILArShape* shape=*shapeHdl;
152
153 // Inputs
155 const LArHitEMap* hitmapPtr = hitmap.cptr();
156 const LArHitEMap* hitmapPtr_DigiHSTruth = nullptr;
157 if ( m_doDigiTruth ) {
158 SG::ReadHandle<LArHitEMap> hitmap_DigitHSTruth(m_hitMapKey_DigiHSTruth,context);
159 hitmapPtr_DigiHSTruth = hitmap_DigitHSTruth.cptr();
160 }
161
162 const size_t nCells=hitmapPtr->GetNbCells();
163 // Prepare Output
164 //
165 // For the standard one lets use a DataPool
166 auto DigitContainer = std::make_unique<LArDigitContainer>(SG::VIEW_ELEMENTS);
167 DigitContainer->reserve(nCells);
168 DataPool<LArDigit> dataItemsPool(context);
169 dataItemsPool.reserve(nCells);
170 //
171 // HSTruth output might not be needed so avoid doing anything
172 // in that case
173 std::unique_ptr<LArDigitContainer> DigitContainer_DigiHSTruth = nullptr;
174 if (m_doDigiTruth){
175 DigitContainer_DigiHSTruth = std::make_unique<LArDigitContainer>();
176 DigitContainer_DigiHSTruth->reserve(nCells);
177 }
178 //
179 const std::vector<std::pair<float,float> >* TimeE;
180 const std::vector<std::pair<float,float> >* TimeE_DigiHSTruth = nullptr;
181
182 ATHRNG::RNGWrapper* rngWrapper = m_rndmGenSvc->getEngine(this, m_randomStreamName);
183 CLHEP::HepRandomEngine * engine = rngWrapper->getEngine(context);
185 rngWrapper->setSeedLegacy( m_randomStreamName, context, m_randomSeedOffset, seedingmode );
186
187 for (size_t it=0;it<nCells;++it)
188 {
189 const LArHitList& hitlist = hitmapPtr->GetCell(it);
190
191 if (!m_Windows || hitlist.inWindows()) {
192 TimeE = &(hitlist.getData());
193 if(m_doDigiTruth) {
194 const auto& hitlist_DigiHSTruth=hitmapPtr_DigiHSTruth->GetCell(it);
195 TimeE_DigiHSTruth = &(hitlist_DigiHSTruth.getData());
196 }
197
198 if (!TimeE->empty() || m_NoiseOnOff || m_RndmEvtOverlay) {
199 const Identifier cellID=m_calocell_id->cell_id(IdentifierHash(it));
200 HWIdentifier ch_id = cabling->createSignalChannelIDFromHash(IdentifierHash(it));
201 HWIdentifier febId = m_laronline_id->feb_Id(ch_id);
202 bool missing=!(badFebs->status(febId).good());
203 if (!missing) {
204 const LArDigit * digit = nullptr ;
205 if(m_RndmEvtOverlay) digit = hitmapPtr->GetDigit(it);
206 // MakeDigit called if in no overlay mode or
207 // if in overlay mode and random digit exists
208 if ((!m_RndmEvtOverlay) || (m_RndmEvtOverlay && digit)) {
209 LArDigit* Digit = nullptr;
210 LArDigit* Digit_DigiHSTruth = nullptr;
211 auto sc = MakeDigit(context, cellID, ch_id, Digit,
212 dataItemsPool,
213 Digit_DigiHSTruth, TimeE, digit, engine,
214 TimeE_DigiHSTruth,
215 adc2MeVs,
216 fSampl,
217 pedestal,
218 noise,
219 autoCorrNoise,
220 bcCont,
221 shape);
222
223 if (sc.isFailure()){
224 ATH_MSG_ERROR("LArHitEMapToDigitAlg::execute failed in MakeDigit");
225 delete Digit_DigiHSTruth;
226 return sc;
227 }
228 DigitContainer->push_back(Digit);
229 if (DigitContainer_DigiHSTruth){
230 DigitContainer_DigiHSTruth->push_back(Digit_DigiHSTruth);
231 }
232 }
233 }
234 }
235 } // check window
236 } // end of loop over the cells
237
238
239 ATH_MSG_DEBUG(" number of created digits = " << DigitContainer->size());
240
241 SG::WriteHandle<LArDigitContainer> DigitContainerHandle( m_DigitContainerName, context);
242 ATH_CHECK(DigitContainerHandle.record( std::move(DigitContainer) ) );
243 if ( DigitContainer_DigiHSTruth ){
244 SG::WriteHandle<LArDigitContainer> DigitContainer_DigiHSTruthHandle( m_DigitContainerName_DigiHSTruth, context);
245 ATH_CHECK(DigitContainer_DigiHSTruthHandle.record( std::move(DigitContainer_DigiHSTruth) ) );
246 }
247
248
249 return StatusCode::SUCCESS;
250}
251
253 const EventContext& ctx,
254 const Identifier& cellId,
255 const HWIdentifier& ch_id,
256 LArDigit*& Digit,
257 DataPool<LArDigit>& dataItemsPool,
258 LArDigit*& Digit_DigiHSTruth,
259 const std::vector<std::pair<float, float>>* TimeE,
260 const LArDigit* rndmEvtDigit,
261 CLHEP::HepRandomEngine* engine,
262 const std::vector<std::pair<float, float>>* TimeE_DigiHSTruth,
263 const LArADC2MeV* adc2MeVs,
264 const ILArfSampl* fSampl,
265 const ILArPedestal* pedestal,
266 const ILArNoise* noise,
267 const LArAutoCorrNoise* autoCorrNoise,
268 const LArBadChannelCont* bcCont,
269 const ILArShape* shape) const {
270
271 bool createDigit_DigiHSTruth = true;
272
273
274 int i;
275 short Adc;
276 short Adc_DigiHSTruth;
277
278 std::vector<short> AdcSample(m_NSamples);
279 std::vector<short> AdcSample_DigiHSTruth(m_NSamples);
280
281 float SF=1.;
282 float SigmaNoise;
283 staticVecFloat_t rndm_energy_samples(m_NSamples) ;
284
285 int iCalo = EM;
286 if (m_larem_id->is_lar_hec(cellId))
287 iCalo = HEC;
288 else if (m_larem_id->is_lar_fcal(cellId))
289 iCalo = FCAL;
290 else if (m_larem_id->is_em_endcap_inner(cellId))
291 iCalo = EMIW;
292
293 CaloGain::CaloGain initialGain=static_cast<CaloGain::CaloGain>(m_gainRange[iCalo].value().first);
295
296// ........ retrieve data (1/2) ................................
297//
298 SF=fSampl->FSAMPL(ch_id);
299
300//
301// ....... dump info ................................
302//
303#ifndef NDEBUG
304 ATH_MSG_DEBUG(" Cellid " << m_larem_id->show_to_string(cellId));
305 ATH_MSG_DEBUG(" SF: " << SF);
306#endif
307
308 staticVecDouble_t Samples;
309 staticVecDouble_t Samples_DigiHSTruth;
310 staticVecDouble_t Noise;
311 Samples.resize(m_NSamples,0);
312 if(m_doDigiTruth) Samples_DigiHSTruth.resize(m_NSamples,0);
313 Noise.resize(m_NSamples,0);
314
315//
316// ....... make the five samples
317//
318
319#ifndef NDEBUG
320 ATH_MSG_DEBUG(" number of hit for this cell " << TimeE->size());
321#endif
322
323//
324// convert Hits into energy samples and add result to Samples assuming LARHIGHGAIN for pulse shape
325//
326 bool isDead = m_bcMask.cellShouldBeMasked(bcCont,ch_id);
327
328
329 if (!isDead) {
330 if( this->ConvertHits2Samples(cellId,ch_id,initialGain,TimeE, Samples, shape).isFailure() ) {
331 return StatusCode::SUCCESS;
332 }
333 if(m_doDigiTruth && TimeE_DigiHSTruth){
334 if( this->ConvertHits2Samples(cellId,ch_id,initialGain,TimeE_DigiHSTruth, Samples_DigiHSTruth, shape).isFailure() ) {
335 return StatusCode::SUCCESS;
336 }
337 }
338 }
339
340//
341// .... add random event digit if needed
342//
343 float energy2adc ;
344 float rAdc ;
345 if(m_RndmEvtOverlay && rndmEvtDigit ) // no overlay if missing random digit
346 {
347 rndmGain= rndmEvtDigit->gain();
348 auto polynom_adc2mev =adc2MeVs->ADC2MEV(ch_id,rndmEvtDigit->gain());
349 if (polynom_adc2mev.size() > 1) {
350 float adc2energy = SF * polynom_adc2mev[1];
351 const std::vector<short> & rndm_digit_samples = rndmEvtDigit->samples() ;
352 float Pedestal = pedestal->pedestal(ch_id,rndmEvtDigit->gain());
353 if (Pedestal <= (1.0+LArElecCalib::ERRORCODE)) {
354 ATH_MSG_WARNING(" Pedestal not found in database for this channel offID " << cellId << " Use sample 0 for random");
355 Pedestal = rndm_digit_samples[0];
356 }
357 ATH_MSG_DEBUG(" Params for inverting LAr Digitization: pedestal " << Pedestal << " adc2energy " << adc2energy);
358
359// in case Medium or low gain, take into account ramp intercept in ADC->"energy" computation
360// this requires to take into account the sum of the optimal filter coefficients, as they don't compute with ADC shift
361 float adc0=0.;
362 if (!m_isMcOverlay && rndmEvtDigit->gain()>0) {
364 if (larOFC.cptr() != nullptr) {
365 ILArOFC::OFCRef_t ofc_a = larOFC->OFC_a(ch_id,rndmEvtDigit->gain(),0);
366 float sumOfc=0.;
367 if (ofc_a.size()>0) {
368 for (unsigned int j=0;j<ofc_a.size();j++) sumOfc += ofc_a.at(j);
369 }
370 if (sumOfc>0) adc0 = polynom_adc2mev[0] * SF /sumOfc;
371 }
372 }
373
374 int nmax=m_NSamples;
375 if ((int)(rndm_digit_samples.size()) < m_NSamples) {
377 "Less digit Samples than requested in digitization for cell "
378 << ch_id.get_compact() << " Digit has " << rndm_digit_samples.size()
379 << " samples. Digitization request " << m_NSamples);
380 nmax = rndm_digit_samples.size();
381 }
382 for(i=0 ; i<nmax ; i++)
383 {
384 rAdc = (rndm_digit_samples[i] - Pedestal ) * adc2energy + adc0;
385 rndm_energy_samples[i] = rAdc ;
386 Samples[i] += rAdc ;
387 }
388 }
389 else {
390 ATH_MSG_WARNING(" No ramp found for this random cell " << m_larem_id->show_to_string(cellId) << " for gain " << rndmEvtDigit->gain());
391 }
392 }
393
394
395 CaloGain::CaloGain igain=chooseGain(Samples,ch_id,static_cast<CaloNum>(iCalo),pedestal,adc2MeVs,SF);
396 if (igain==CaloGain::INVALIDGAIN) {
397 return StatusCode::FAILURE;
398 }
399
400 // check that select gain is never lower (higher index number) than random gain in case of overlay
401 igain=std::max(rndmGain,igain);
402
403//
404// recompute Samples if igain != HIGHGAIN
405//
406 if (igain != initialGain ){
407 for (i=0;i<m_NSamples;i++) {
408 if(m_doDigiTruth) Samples_DigiHSTruth[i] = 0.;
409 if (m_RndmEvtOverlay) Samples[i]= rndm_energy_samples[i] ;
410 else Samples[i] = 0.;
411 }
412
413 if (!isDead) {
414 if( this->ConvertHits2Samples(cellId,ch_id,igain,TimeE, Samples, shape) == StatusCode::FAILURE ) {
415 return StatusCode::SUCCESS;
416 }
417 if(m_doDigiTruth){
418 if( this->ConvertHits2Samples(cellId,ch_id,igain,TimeE_DigiHSTruth, Samples_DigiHSTruth, shape) == StatusCode::FAILURE ) {
419 return StatusCode::SUCCESS;
420 }
421 }
422 }
423 }
424
425//
426// ........ add the noise ................................
427//
428
429 double Rndm[32]{};
430 int BvsEC=0;
431 if(iCalo==EM || iCalo==EMIW) BvsEC=std::abs(m_larem_id->barrel_ec(cellId));
432
433 bool addedNoise=false;
434 if (m_NoiseOnOff &&
435 ((BvsEC == 1 && m_NoiseInEMB) || (BvsEC > 1 && m_NoiseInEMEC) ||
436 (iCalo == HEC && m_NoiseInHEC) || (iCalo == FCAL && m_NoiseInFCAL)))
437 // add the noise only in the wanted sub-detectors
438 {
439 if (!m_RndmEvtOverlay) {
440 if (!m_pedestalNoise) {
441 SigmaNoise = noise->noise(ch_id, igain);
442 } else {
443 float thisNoise = pedestal->pedestalRMS(ch_id, igain);
444 if (thisNoise >= (1.0 + LArElecCalib::ERRORCODE))
445 SigmaNoise = thisNoise;
446 else
447 SigmaNoise = 0.;
448 }
449 // Sqrt of noise covariance matrix
450 const std::vector<float>& CorGen =
451 autoCorrNoise->autoCorrSqrt(cellId, igain);
452 if (CorGen.size() < (unsigned)m_NSamples * m_NSamples) {
453 ATH_MSG_ERROR("Noise AutoCorr too small, need "
454 << m_NSamples * m_NSamples << " points for "
455 << m_NSamples << " samples.");
456 return StatusCode::FAILURE;
457 }
458
459 RandGaussZiggurat::shootArray(engine, m_NSamples, Rndm, 0., 1.);
460
461 int index;
462 for (int i = 0; i < m_NSamples; i++) {
463 Noise[i] = 0.;
464 for (int j = 0; j <= i; j++) {
465 index = i * m_NSamples + j;
466 Noise[i] += Rndm[j] * CorGen[index];
467 }
468 Noise[i] = Noise[i] * SigmaNoise;
469 }
470 addedNoise = true;
471 } else {
472 // overlay case a priori don't add any noise
473 for (int i = 0; i < m_NSamples; i++)
474 Noise[i] = 0.;
475 // if gain from zerobias events is < gain from mixed events => add extra
476 // noise to account for gain vs noise dependance
477 // done in a simple way without taking into account the time
478 // correlation of this extra noise properly
479 if (rndmEvtDigit) {
480 // if gain of cell is different from ZB event gain
481 if (igain > rndmEvtDigit->gain()) {
482 double SigmaNoiseZB = 0.; // noise in ZB event for gain of ZB event
483 double SigmaNoise = 0.; // noise expected for new gain value
484 double SigmaExtraNoise = 0.; // quadratic difference of noise values
485 if (!m_pedestalNoise) {
486 SigmaNoiseZB = noise->noise(ch_id, rndmEvtDigit->gain());
487 SigmaNoise = noise->noise(ch_id, igain);
488 } else {
489 float thisNoise = pedestal->pedestalRMS(ch_id, rndmEvtDigit->gain());
490 if (thisNoise >= (1.0 + LArElecCalib::ERRORCODE))
491 SigmaNoiseZB = thisNoise;
492 else
493 SigmaNoiseZB = 0.;
494 thisNoise = pedestal->pedestalRMS(ch_id, igain);
495 if (thisNoise >= (1.0 + LArElecCalib::ERRORCODE))
496 SigmaNoise = thisNoise;
497 else
498 SigmaNoise = 0.;
499 }
500 // Convert SigmaNoiseZB in noise in ADC counts for igain conversion
501 auto polynom_adc2mevZB =
502 adc2MeVs->ADC2MEV(cellId, rndmEvtDigit->gain());
503 auto polynom_adc2mev = adc2MeVs->ADC2MEV(cellId, igain);
504 if (polynom_adc2mevZB.size() > 1 && polynom_adc2mev.size() > 1) {
505 if (polynom_adc2mev[1] > 0.) {
506 SigmaNoiseZB = SigmaNoiseZB * (polynom_adc2mevZB[1]) /
507 (polynom_adc2mev[1]);
508 if (SigmaNoise > SigmaNoiseZB)
509 SigmaExtraNoise = sqrt(SigmaNoise * SigmaNoise -
510 SigmaNoiseZB * SigmaNoiseZB);
511 }
512 } // check that AC2MeV factors are there
513 RandGaussZiggurat::shootArray(engine, m_NSamples, Rndm, 0.,
514 1.); // generate noise
515 for (int i = 0; i < m_NSamples; i++)
516 Noise[i] = SigmaExtraNoise * Rndm[i];
517 addedNoise = true;
518 } // different gains
519 } // rndm Digit is there
520 } // rndm Overlay test
521 } // add noise ?
522 //
523// ......... convert into adc counts ................................
524//
525 float Pedestal = pedestal->pedestal(ch_id,igain);
526 if (Pedestal <= (1.0+LArElecCalib::ERRORCODE)) {
527 ATH_MSG_WARNING(" pedestal not found for cellId " << cellId << " assume 1000" );
528 Pedestal=1000.;
529 }
530 const auto polynom_adc2mev = adc2MeVs->ADC2MEV(cellId,igain);
531 if (polynom_adc2mev.size() < 2) {
532 ATH_MSG_WARNING(" No ramp found for requested gain " << igain << " for cell " << m_larem_id->show_to_string(cellId) << " no digit made...");
533 return StatusCode::SUCCESS;
534 }
535
536 energy2adc=1./(polynom_adc2mev[1])/SF;
537
538// in case Medium or low gain, take into account ramp intercept in energy->ADC computation
539// this requires to take into account the sum of the optimal filter coefficients, as they don't compute with ADC shift
540 if(!m_isMcOverlay && m_RndmEvtOverlay && igain>0)
541 {
543 if (larOFC.cptr() != nullptr) {
544 float sumOfc=0.;
545 ILArOFC::OFCRef_t ofc_a = larOFC->OFC_a(ch_id,igain,0);
546 if (ofc_a.size()>0) {
547 for (unsigned int j=0;j<ofc_a.size();j++) sumOfc+= ofc_a.at(j);
548 }
549 if ((polynom_adc2mev[1])>0 && sumOfc>0) Pedestal = Pedestal - (polynom_adc2mev[0])/(polynom_adc2mev[1])/sumOfc;
550 ATH_MSG_DEBUG(" Params for final LAr Digitization gain: " << igain << " pedestal: " << Pedestal << " energy2adc: " << energy2adc);
551 }
552 }
553 for(i=0;i<m_NSamples;i++)
554 {
555 double xAdc;
556 double xAdc_DigiHSTruth = 0;
557
558 if ( addedNoise ){
559 xAdc = Samples[i]*energy2adc + Noise[i] + Pedestal + 0.5;
560 if(m_doDigiTruth) {
561 xAdc_DigiHSTruth = Samples_DigiHSTruth[i]*energy2adc + Noise[i] + Pedestal + 0.5;
562 }
563 }
564
565 else {
566 if (m_roundingNoNoise) {
567 float flatRndm = RandFlat::shoot(engine);
568 xAdc = Samples[i]*energy2adc + Pedestal + flatRndm;
569 if(m_doDigiTruth) {
570 xAdc_DigiHSTruth = Samples_DigiHSTruth[i]*energy2adc + Pedestal + flatRndm;
571 }
572
573 }
574 else{
575 xAdc = Samples[i]*energy2adc + Pedestal + 0.5;
576 if(m_doDigiTruth) {
577 xAdc_DigiHSTruth = Samples_DigiHSTruth[i]*energy2adc + Pedestal + 0.5;
578 }
579 }
580
581 }
582
583//
584// ........ truncate at maximum value + 1
585// add possibility to saturate at 0 for negative signals
586//
587 if (xAdc <0) Adc=0;
588 else if (xAdc >= m_maxADC) Adc=m_maxADC;
589 else Adc = (short) xAdc;
590
591 AdcSample[i]=Adc;
592
593 if(m_doDigiTruth){
594 if (xAdc_DigiHSTruth <0) Adc_DigiHSTruth=0;
595 else if (xAdc_DigiHSTruth >= m_maxADC) Adc_DigiHSTruth=m_maxADC;
596 else Adc_DigiHSTruth = (short) xAdc_DigiHSTruth;
597 AdcSample_DigiHSTruth[i] = Adc_DigiHSTruth;
598 }
599
600#ifndef NDEBUG
601 ATH_MSG_DEBUG(" Sample " << i << " Energy= " << Samples[i] << " Adc=" << Adc);
602#endif
603
604 }
605
606//
607// ...... create the LArDigit .............
608//
609 Digit = dataItemsPool.nextElementPtr();
610 (*Digit)=LArDigit(ch_id,igain,std::move(AdcSample));
611
612 if (m_doDigiTruth && createDigit_DigiHSTruth) {
613 createDigit_DigiHSTruth = false;
614 Digit_DigiHSTruth = nullptr;
615
616 for (int i = 0; i < m_NSamples; i++) {
617 if (Samples_DigiHSTruth[i] != 0)
618 createDigit_DigiHSTruth = true;
619 }
620
621 Digit_DigiHSTruth =
622 new LArDigit(ch_id, igain, std::move(AdcSample_DigiHSTruth));
623 }
624
625 return StatusCode::SUCCESS;
626}
627
628// ---------------------------------------------------------------------------------------
629
631 const std::vector<std::pair<float,float> > *TimeE, staticVecDouble_t &sampleList,
632 const ILArShape* shape) const
633
634{
635// Converts hits of a particular LAr cell into energy samples
636// declarations
637 int nsamples ;
638 int nsamples_der ;
639 int i ;
640 int j ;
641
642// ........ retrieve data (1/2) ................................
643//
644 ILArShape::ShapeRef_t Shape = shape->Shape(ch_id,igain);
645 ILArShape::ShapeRef_t ShapeDer = shape->ShapeDer(ch_id,igain);
646
647 nsamples = Shape.size();
648 nsamples_der = ShapeDer.size();
649
650 if (nsamples==0) {
651 ATH_MSG_INFO(" No samples for cell = " << cellId );
652 return StatusCode::FAILURE;
653 }
654
655#ifndef NDEBUG
656 ATH_MSG_DEBUG(" Cellid " << m_larem_id->show_to_string(cellId));
657 for (i=0;i<nsamples;i++)
658 {
659 ATH_MSG_DEBUG(Shape[i] << " ");
660 }
661 ATH_MSG_DEBUG("m_NSamples, m_usePhase " << m_NSamples << " " << m_usePhase);
662#endif
663
664
665for (const auto& [energy, time] : *TimeE) {
666 // fix the shift +1 if HEC and nSamples 4 and firstSample 0
667 // in case of data overlay this should NOT be done as the pulse shape read from the database is already shifted
668 // but this should still be done in case of MC overlay
669 int ihecshift=0;
670 if((!m_RndmEvtOverlay || m_isMcOverlay) && m_larem_id->is_lar_hec(cellId) && m_NSamples.value() == 4 && m_firstSample.value() == 0) ihecshift=1;
671
672
673 if (!m_usePhase) {
674
675 // Atlas like mode where we use 25ns binned pulse shape and derivative to deal with time offsets
676
677// shift between reference shape and this time
678 int ishift=(int)(rint(time*(1./25.)));
679 double dtime=time-25.*((double)(ishift));
680 for (i=0;i<m_NSamples.value();i++)
681 {
682 j = i - ishift + m_firstSample + ihecshift;
683#ifndef NDEBUG
684 ATH_MSG_DEBUG(" time/i/j " << time << " "<< i << " " << j);
685#endif
686 if (j >=0 && j < nsamples ) {
687 if (j<nsamples_der && std::abs(ShapeDer[j])<10. )
688 sampleList[i] += (Shape[j]- ShapeDer[j]*dtime)*energy ;
689 else sampleList[i] += Shape[j]*energy ;
690 }
691 }
692 }
693// Mode to use phase (tbin) to get pulse shape ( pulse shape with fine time binning should be available)
694
695 else {
696
697 // FIXME hardcode 8phases3ns configuration (cannot access parameters from ILArShape interface now)
698 int nTimeBins = 8;
699 float timeBinWidth = 25./24.*3.;
700
701// -50<t<-25 phase=-t-25, shift by one peak time (for s2 uses shape(3) with tbin)
702// for -25<t<0 phase = -t, no shift of peak time
703// for 0<t<25 phase=25-t, shift by one peak time (for s2 uses shape(1) with tbin)
704// 25<t<50 phase=50-t, shift by two
705// etc...
706
707 int ishift = (int)(time*(1./25.));
708 int tbin;
709 if (time>0) {
710 tbin = (int)(fmod(time,25)/timeBinWidth);
711 if (tbin>0) {
712 tbin=nTimeBins-tbin;
713 ishift +=1;
714 }
715 } else {
716 tbin = (int)(fmod(-time,25)/timeBinWidth);
717 }
718
719 double dtime = time - ( 25.*((float)(ishift)) - timeBinWidth*tbin);
720
721 Shape = shape->Shape(ch_id,igain,tbin);
722 ShapeDer = shape->ShapeDer(ch_id,igain,tbin);
723
724 nsamples = Shape.size();
725 nsamples_der = ShapeDer.size();
726
727
728 for (i=0;i<m_NSamples.value();i++)
729 {
730 j = i - ishift+m_firstSample + ihecshift;
731#ifndef NDEBUG
732 ATH_MSG_DEBUG(" time/i/j " << time << " "<< i << " " << j);
733#endif
734 if (j >=0 && j < nsamples ) {
735 if (j<nsamples_der && std::abs(ShapeDer[j])<10. )
736 sampleList[i] += (Shape[j]- ShapeDer[j]*dtime)*energy ;
737 else sampleList[i] += Shape[j]*energy ;
738 }
739 }
740
741 } // else if of m_usePhase
742 } // loop over hits
743
744 return StatusCode::SUCCESS;
745
746}
747
749 const ILArPedestal* pedestal, const LArADC2MeV* adc2MeVs, const float SF) const {
750
751 int sampleGainChoice{2};
752 if (m_firstSample < 0)
753 sampleGainChoice -= m_firstSample;
754
755 // fix the shift +1 if HEC and nSamples 4 and firstSample 0
756 if (iCalo == HEC && m_NSamples.value() == 4 && m_firstSample.value() == 0)
757 sampleGainChoice -= 1; // ihecshift
758
759 CaloGain::CaloGain gainChoosingGain = static_cast<CaloGain::CaloGain>(m_gainRange[iCalo].value().second - 1);
760 // We choose the gain in applying thresholds on the 3rd Sample (index "2")
761 // converted in ADC counts in the second-lowest gain (eg MEDIUM gain for run 1,2,3, HIGH gain for run 4)
762 // Indeed, thresholds in ADC counts are defined with respect to the MediumGain.
763 //
764 // 1300 3900
765 // ---------------|----------------|--------------> ADC counts in MediumGain
766 // HighGain <--- MediumGain ---> LowGain
767
768 float Pedestal = pedestal->pedestal(ch_id, gainChoosingGain);
769 if (Pedestal <= (1.0 + LArElecCalib::ERRORCODE)) {
770 ATH_MSG_DEBUG(" Pedestal not found for channel " << m_laronline_id->channel_name(ch_id) << " assume 1000 ");
771 Pedestal = 1000.;
772 }
773 const auto& polynom_adc2mev = adc2MeVs->ADC2MEV(ch_id, gainChoosingGain);
774 if (polynom_adc2mev.size() < 2) {
775 ATH_MSG_WARNING(" No ramp found for channel " << m_laronline_id->channel_name(ch_id) << ", gain " << gainChoosingGain << ", no digit produced...");
777 }
778 const float pseudoADC3 = samples[sampleGainChoice] / (polynom_adc2mev[1]) / SF + Pedestal;
779
780 CaloGain::CaloGain igain = gainChoosingGain;
781 // if we are not yet already in the highest gain and we are below high-gain theshold, switch to high gain
782 if (gainChoosingGain > m_gainRange[iCalo].value().first && pseudoADC3 < m_HighGainThresh[iCalo]) {
783 igain = CaloGain::LARHIGHGAIN;
784 }
785
786 else if (gainChoosingGain < m_gainRange[iCalo].value().second && pseudoADC3 > m_LowGainThresh[iCalo]) {
787 igain = CaloGain::LARLOWGAIN;
788 }
789
790 return igain;
791}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Definition of CaloDetDescrManager.
interface to a tool that returns the time offset of the current trigger.
LArBadXCont< LArBadFeb > LArBadFebCont
LArBadXCont< LArBadChannel > LArBadChannelCont
static Double_t sc
const int nmax(200)
Handle class for recording to StoreGate.
A wrapper class for event-slot-local random engines.
Definition RNGWrapper.h:56
SeedingOptionType
Options for seeding option=0 is setSeed as in MC20 option=1 is setSeedLegacy as in MC16 option=2 is s...
Definition RNGWrapper.h:97
void setSeedLegacy(const std::string &algName, size_t slot, uint64_t ev, uint64_t run, uint64_t offset, SeedingOptionType seeding, EventContext::ContextEvt_t evt=EventContext::INVALID_CONTEXT_EVT)
Set the random seed using a string (e.g.
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition RNGWrapper.h:134
const ServiceHandle< StoreGateSvc > & detStore() const
This class initializes the Calo (LAr and Tile) offline identifiers.
const LArHEC_ID * getHEC_ID(void) const
const LArFCAL_ID * getFCAL_ID(void) const
const LArEM_ID * getEM_ID(void) const
a typed memory pool that saves time spent allocation small object.
Definition DataPool.h:63
void reserve(unsigned int size)
Set the desired capacity.
pointer nextElementPtr()
obtain the next available element in pool by pointer pool is resized if its limit has been reached On...
LArVectorProxy OFCRef_t
This class defines the interface for accessing Optimal Filtering coefficients for each channel provid...
Definition ILArOFC.h:26
virtual float pedestal(const HWIdentifier &id, int gain) const =0
virtual float pedestalRMS(const HWIdentifier &id, int gain) const =0
access to RMS of Pedestal index by Identifier, and gain setting
LArVectorProxy ShapeRef_t
This class defines the interface for accessing Shape (Nsample variable, Dt = 25 ns fixed) @stereotype...
Definition ILArShape.h:26
virtual ShapeRef_t Shape(const HWIdentifier &id, int gain, int tbin=0, int mode=0) const =0
virtual ShapeRef_t ShapeDer(const HWIdentifier &id, int gain, int tbin=0, int mode=0) const =0
virtual const float & FSAMPL(const HWIdentifier &id) const =0
This is a "hash" representation of an Identifier.
value_type get_compact() const
Get the compact id.
const LArVectorProxy ADC2MEV(const HWIdentifier &id, int gain) const
Definition LArADC2MeV.h:32
const std::vector< float > & autoCorrSqrt(const HWIdentifier &id, int gain) const
LArBC_t status(const HWIdentifier channel) const
Query the status of a particular channel or FEB This is the main client access method.
Liquid Argon digit base class.
Definition LArDigit.h:25
CaloGain::CaloGain gain() const
Definition LArDigit.h:72
const std::vector< short > & samples() const
Definition LArDigit.h:78
Gaudi::Property< bool > m_usePhase
Gaudi::Property< bool > m_isMcOverlay
const LArHEC_ID * m_larhec_id
Gaudi::Property< std::vector< std::string > > m_problemsToMask
static constexpr int s_MaxNSamples
Gaudi::Property< bool > m_NoiseInEMEC
Gaudi::Property< bool > m_doDigiTruth
SG::ReadHandleKey< LArHitEMap > m_hitMapKey
SG::ReadCondHandleKey< LArADC2MeV > m_adc2mevKey
StatusCode ConvertHits2Samples(const Identifier &cellId, HWIdentifier ch_id, CaloGain::CaloGain igain, const std::vector< std::pair< float, float > > *TimeE, staticVecDouble_t &sampleList, const ILArShape *shape) const
const CaloCell_ID * m_calocell_id
Gaudi::Property< bool > m_pedestalNoise
Gaudi::Property< bool > m_roundingNoNoise
SG::ReadHandleKey< LArHitEMap > m_hitMapKey_DigiHSTruth
StatusCode MakeDigit(const EventContext &ctx, const Identifier &cellId, const HWIdentifier &ch_id, LArDigit *&Digit, DataPool< LArDigit > &dataItemsPool, LArDigit *&Digit_DigiHSTruth, const std::vector< std::pair< float, float > > *TimeE, const LArDigit *rndm_digit, CLHEP::HepRandomEngine *engine, const std::vector< std::pair< float, float > > *TimeE_DigiHSTruth, const LArADC2MeV *adc2MeVs, const ILArfSampl *fSampl, const ILArPedestal *pedestal, const ILArNoise *noise, const LArAutoCorrNoise *autoCorrNoise, const LArBadChannelCont *bcCont, const ILArShape *shape) const
std::array< Gaudi::Property< std::pair< int, int > >, 4 > m_gainRange
virtual StatusCode execute(const EventContext &context) const
Gaudi::Property< uint32_t > m_randomSeedOffset
Gaudi::Property< bool > m_NoiseInEMB
SG::ReadCondHandleKey< LArBadChannelCont > m_bcContKey
Gaudi::Property< int > m_firstSample
SG::WriteHandleKey< LArDigitContainer > m_DigitContainerName_DigiHSTruth
const LArOnlineID * m_laronline_id
Gaudi::Property< bool > m_NoiseInHEC
boost::container::static_vector< double, s_MaxNSamples > staticVecDouble_t
Gaudi::Property< bool > m_useLegacyRandomSeeds
const LArFCAL_ID * m_larfcal_id
SG::ReadCondHandleKey< LArOnOffIdMapping > m_cablingKey
std::array< Gaudi::Property< double >, 4 > m_LowGainThresh
virtual StatusCode initialize()
SG::ReadCondHandleKey< ILArPedestal > m_pedestalKey
SG::ReadCondHandleKey< ILArNoise > m_noiseKey
CaloGain::CaloGain chooseGain(const staticVecDouble_t &samples, const HWIdentifier id, const CaloNum iCalo, const ILArPedestal *ped, const LArADC2MeV *ramp, const float SF) const
SG::ReadCondHandleKey< CaloDetDescrManager > m_caloMgrKey
Gaudi::Property< bool > m_Windows
Gaudi::Property< bool > m_NoiseOnOff
std::array< Gaudi::Property< double >, 4 > m_HighGainThresh
boost::container::static_vector< float, s_MaxNSamples > staticVecFloat_t
Gaudi::Property< bool > m_RndmEvtOverlay
Gaudi::Property< int > m_NSamples
SG::ReadCondHandleKey< ILArOFC > m_OFCKey
ServiceHandle< IAthRNGSvc > m_rndmGenSvc
SG::ReadCondHandleKey< LArAutoCorrNoise > m_autoCorrNoiseKey
const T * pointerFromKey(const EventContext &context, const SG::ReadCondHandleKey< T > &key) const
Gaudi::Property< bool > m_NoiseInFCAL
SG::ReadCondHandleKey< LArBadFebCont > m_badFebKey
SG::ReadCondHandleKey< ILArfSampl > m_fSamplKey
Gaudi::Property< unsigned > m_maxADC
SG::WriteHandleKey< LArDigitContainer > m_DigitContainerName
SG::ReadCondHandleKey< ILArShape > m_shapeKey
Gaudi::Property< std::string > m_randomStreamName
size_t GetNbCells(void) const
Definition LArHitEMap.h:42
const LArHitList & GetCell(const unsigned int index) const
Definition LArHitEMap.h:43
const LArDigit * GetDigit(unsigned int index) const
Definition LArHitEMap.h:48
bool inWindows() const
Definition LArHitList.h:26
const LARLIST & getData() const
Definition LArHitList.h:25
value_type at(size_t i) const
Vector indexing with bounds check.
const_pointer_type cptr()
const_pointer_type cptr()
Dereference the pointer.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
@ INVALIDGAIN
Definition CaloGain.h:18
@ LARLOWGAIN
Definition CaloGain.h:18
@ LARHIGHGAIN
Definition CaloGain.h:18
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
Definition index.py:1