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