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