ATLAS Offline Software
Loading...
Searching...
No Matches
TilePulseForTileMuonReceiver.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5//***************************************************************************************
6//
7// Filename : TilePulseForTileMuonReceiver.cxx
8// Author : Joao Gentil Mendes Saraiva (jmendes@cern.ch)
9// Created : October 2013
10//
11// DESCRIPTION:
12//
13// The algorithm will do:
14// Create a digitized pulse with 7 samples based in a measured pulse.
15// The pulse is reconstructed using the matched filter alogtrithm.
16// Digits and reconstructed pulse parameters (e,t,qf) are saved in contaienrs in TES.
17//
18// This is part of the tile-d project (2015).
19//
20// HISTORY:
21//
22// 10.dec.2013 ready for submission in svn
23// 16.jan.2014 fixed coverity errors
24// 06.oct.2015 including the barrel cells
25// 21.jun.2020 MC pileup overlay
26//
27// BUGS:
28//
29//
30//
31//****************************************************************************************
32
33// Tile includes
43
44
45// Calo includes
47
48// Atlas includes
56
57
58// external
59#include <CLHEP/Random/Randomize.h>
60#include <CLHEP/Units/SystemOfUnits.h>
61
62using CLHEP::RandGaussQ;
63using CLHEP::RandFlat;
64using CLHEP::MeV;
65
66#include "cmath"
67
68// constructor
69//
70TilePulseForTileMuonReceiver::TilePulseForTileMuonReceiver(const std::string& name, ISvcLocator* pSvcLocator)
71 : AthAlgorithm(name, pSvcLocator)
72 , m_tileID(nullptr)
73 , m_tileHWID(nullptr)
74 , m_tileInfo(nullptr)
75 , m_cablingService(nullptr)
76 , m_nSamples(0)
77 , m_iTrig(0)
78 , m_adcMax(0)
79 , m_tileThresh(0.0)
80 , m_nShape(0)
81 , m_nBinsPerX(0)
82 , m_binTime0(0)
83 , m_timeStep(0.0)
84 , m_runPeriod(0)
85{
86}
87
88// destructor
89//
92
93// initialize
94//
96
97 // Check cabling RUN>=RUN2 OK
98 //
99 ATH_CHECK( m_cablingSvc.retrieve() );
100 m_cablingService = m_cablingSvc->cablingService();
101 m_runPeriod = m_cablingService->runPeriod();
102
103 // Handles must always be initialised
104 ATH_CHECK( m_hitContainerKey.initialize(m_runPeriod != 0) );
108 ATH_CHECK( m_samplingFractionKey.initialize(m_runPeriod != 0) );
109 ATH_CHECK( m_emScaleKey.initialize(m_runPeriod != 0) );
111
112 if ( m_runPeriod == 0) {
113 ATH_MSG_INFO("TilePulseForTileMuonReceiver should not be used for RUN1 simulations");
114 return StatusCode::SUCCESS;
115 } else {
116 ATH_MSG_INFO("Initializing TilePulseForTileMuonReceiver");
117 }
118
119 //=== retrieve TileID helper and TileInfo from det store
120 ATH_CHECK(detStore()->retrieve(m_tileID));
121 ATH_CHECK(detStore()->retrieve(m_tileHWID));
123
124 ATH_CHECK(m_MuRcvBuildTool.retrieve());
125
126 m_nSamples = m_tileInfo->NdigitSamples(); // number of time slices for each chan
127 m_iTrig = m_tileInfo->ItrigSample(); // index of the triggering time slice
128 m_adcMax = m_tileInfo->ADCmax(); // adc saturation value
129 m_tileThresh = m_tileInfo->ThresholdDigits(TileID::LOWGAIN);
130
131 ATH_MSG_VERBOSE("Cabling Services: " << m_cablingService
132 << " Number of Samples: " << m_nSamples
133 << " Triggering tile slice: " << m_iTrig
134 << " ADC saturation value: " << m_adcMax
135 << " TileCal Threshold LOW GAIN: " << m_tileThresh);
136
137 ATH_CHECK(m_rndmSvc.retrieve());
138
139 m_nShape = m_tileInfo->MuRcvNBins();
140 m_nBinsPerX = m_tileInfo->MuRcvBinsPerX();
141 m_binTime0 = m_tileInfo->MuRcvTime0Bin();
142 m_timeStep = 25.0 / m_nBinsPerX;
143
144 ATH_MSG_VERBOSE( "Pulse info : "
145 << "shape " << m_nShape
146 <<" nbins " << m_nBinsPerX
147 <<" time " << m_binTime0
148 <<" time step " << m_timeStep
149 <<" Triggering tile sample " << m_iTrig);
150
151 // decrease by 1, now it is the position of lastest element in a vector
152 //
153 --m_nShape;
154
157 ATH_MSG_INFO( "Using pulse from database.");
158 } else {
159 ATH_MSG_INFO( "Using pulse from TileInfo.");
160
161 m_shapeMuonReceiver = m_tileInfo->MuRcvFullShape();
162 m_shapeMuonReceiver.push_back(0.0);
163 }
164
166
167 ATH_MSG_INFO( "Integer digits: \t" << ((m_integerDigits)?"true":"false"));
168 ATH_MSG_INFO( "Tile Pedestal: \t" << ((m_tilePedestal)?"true":"false"));
169 ATH_MSG_INFO( "Tile Noise: \t" << ((m_tileNoise)?"true":"false"));
170 ATH_MSG_INFO( "Event Overlay: \t" << ((m_rndmEvtOverlay)?"true":"false"));
171 ATH_MSG_INFO( "Masking Channels: \t" << ((m_maskBadChannels)?"true":"false"));
172 ATH_MSG_INFO( "Pulse shapes from COOL: \t" << ((m_useCoolPulseShapes)?"true":"false"));
173
175
176 if (m_rndmEvtOverlay) {
177 ATH_MSG_INFO( "Pileup and/or noise added by overlaying digits of random events");
178 // locate the PileUpMergeSvc and initialize our local ptr
180 ATH_CHECK( m_mergeSvc.retrieve() );
181 ATH_MSG_INFO( "PileUpMergeSvc successfully initialized");
182 }
183 }
184
185 ATH_MSG_VERBOSE("TilePulseForTileMuonReceiver initialization completed");
186 return StatusCode::SUCCESS;
187}
188
189// execute
190//
192
193 if (m_runPeriod==0) {
194 ATH_MSG_VERBOSE( "ATT: RUN1 settings TilePulseForTileMuonReceiver will end now" );
195 return StatusCode::SUCCESS;
196 } else {
197 ATH_MSG_DEBUG( "Executing TilePulseForTileMuonReceiver" );
198 }
199
200 const EventContext& ctx = Gaudi::Hive::currentContext();
201
202 // Conversion from TMDB channel number to channel number in a drawer: EB (0-3) LB (0-8)
203 // Including the cells used in the "The potential of using the ATLAS Tile calorimeter in Phase-II for the
204 // Level-0 muon trigger" (ATL-COM-TILECAL-2015-007.pdf): ALL D-layer + BC-8.
205 //
206#define nEBchan 6
207#define nLBchan 9
208 // EB: D5(L,R),D6(L,R),D4(L,R)
209 int EBchan[nEBchan]={17,16,37,38,3,2};
210 // LB: D0,D1(L,R),D2(L,R),D3(L,R),BC8(L,R)
211 int LBchan[nLBchan]={0,13,14,25,24,41,44,39,40};
212 // Set to maximum possible index
213#if (nEBchan > nLBchan)
214 double pDigitSamplesArray[nEBchan][7];
215 double pDigitSamplesRndmArray[nEBchan][7];
216#else
217 double pDigitSamplesArray[nLBchan][7];
218 double pDigitSamplesRndmArray[nLBchan][7];
219#endif
220
221 // PULSE
222
223 // Random generators output arrays
224 //
225 double Rndm[16];
226 double Rndm_dG[1];
227
228 // Noise and pedestal from db
229 //
230 double pedSim = 0.;
231 double sigma_Hfn1 = 0.;
232 double sigma_Hfn2 = 0.;
233 double sigma_Norm = 0.;
234 double sigmaSim(0.0);
235
236 // Measured parameters: noise, pedestal and calibration
237 //
238 double muRcv_NoiseSigma;
239 double muRcv_Ped;
240 double muRcv_Calib;
241 double muRcv_Max;
242
244 ATH_CHECK( emScale.isValid() );
245
246 const TileBadChannels* badChannels = nullptr;
247 if (m_maskBadChannels) {
249 ATH_CHECK( badChannelsHandle.isValid() );
250 badChannels = *badChannelsHandle;
251 }
252
253 const TilePulse* pulse = nullptr;
256 ATH_CHECK( pulseShape.isValid() );
257 pulse = pulseShape.retrieve();
258 }
259
260 const TileSampleNoise* sampleNoise = nullptr;
263 ATH_CHECK( sampleNoiseHandle.isValid() );
264 sampleNoise = sampleNoiseHandle.retrieve();
265 }
266
267 // Get hit container from TES
268 //
270 ATH_CHECK( hitContainer.isValid() );
271
272 // Set up buffers for handling information in a single collection.
273 //
274 IdentifierHash idhash;
275 IdContext drawer_context = m_tileHWID->drawer_context();
276
277 // Get a container for the digits
278 //
279 auto muRcvDigitsContainer = std::make_unique<TileMutableDigitsContainer>(true,
282 ATH_CHECK( muRcvDigitsContainer->status() );
283
284 // Get a container for the raw channels
285 //
286 auto muRcvRawChannelContainer = std::make_unique<TileMutableRawChannelContainer>(true,
290 ATH_CHECK( muRcvRawChannelContainer->status() );
291
292 // Prepare container for MC Overlay procedure
293 //
296 std::unique_ptr<TileMutableDigitsContainer> backgroundDigitContainer{};
297
298 if (m_rndmEvtOverlay) {
299
300 ATH_MSG_DEBUG("Prepare background container for MC Overlay procedure");
301
302 backgroundDigitContainer = std::make_unique<TileMutableDigitsContainer>(true,
305 ATH_CHECK( backgroundDigitContainer->status() );
306
309 TimedDigitContList digitContList;
310 ATH_CHECK( m_mergeSvc->retrieveSubEvtsData(m_inputDigitContainerName, digitContList));
311 ATH_MSG_DEBUG( "TileDigitsCnt successfully retrieved ");
312
313 if (digitContList.size() == 0) {
314 ATH_MSG_WARNING( "No overlay done ... ");
315 return StatusCode::SUCCESS;
316 }
317
318 TimedDigitContList::iterator iTzeroDigitCont(digitContList.begin());
319 for (const auto* digitCollection : *(iTzeroDigitCont->second)) {
320 for (const auto* digit : *digitCollection) {
321 auto pDigits = std::make_unique<TileDigits>(*digit);
322 ATH_CHECK(backgroundDigitContainer->push_back(std::move(pDigits)));
323 }
324 }
325 } else {
327 if (tileDigitsContainerHandle.isValid()) {
328 for (const auto* digitCollection : *tileDigitsContainerHandle) {
329 for (const auto* digit : *digitCollection) {
330 auto pDigits = std::make_unique<TileDigits>(*digit);
331 ATH_CHECK(backgroundDigitContainer->push_back(std::move(pDigits)));
332 }
333 }
334 } else {
335 ATH_MSG_ERROR("ReadHandle to Background Digits is invalid.");
336 return StatusCode::FAILURE;
337 }
338 }
339
340 collItrRndm = backgroundDigitContainer->begin();
341 lastCollRndm = backgroundDigitContainer->end();
342 }
343
344 // Vector of digits to set into the container
345 //
346 std::vector<float> digitsBuffer(m_nSamples);
347
348 // Vector(s) for MC Overlay procedure
349 //
350 std::vector<float> digitsBuffer_rndm(m_nSamples);
351 std::vector<bool> good_bkg( 9 , false );
352
353 // Prepare RNG service
354 //
355 ATHRNG::RNGWrapper* rngWrapper = m_rndmSvc->getEngine(this, m_randomStreamName);
356 rngWrapper->setSeed( m_randomStreamName, ctx );
357 CLHEP::HepRandomEngine* rndmEngine = rngWrapper->getEngine(ctx);
358
360 // (a.0) iterate over collections in the HIT container: access 'ros' and 'drawer'
361 //
363 ATH_CHECK( samplingFraction.isValid() );
364
365 for (const TileHitCollection* hitCollection : *hitContainer) {
366
367 // Get array of HWID's for this drawer (stored locally).
368 //
369 HWIdentifier drawer_id = m_tileHWID->drawer_id(hitCollection->identify());
370 int ros = m_tileHWID->ros(drawer_id);
371 int drawer = m_tileHWID->drawer(drawer_id);
372 int drawerIdx = TileCalibUtils::getDrawerIdx(ros, drawer);
373 bool eb_ros = ((ros == TileHWID::EXTBAR_POS) || (ros == TileHWID::EXTBAR_NEG));
374 int upperLim = (eb_ros) ? nEBchan : nLBchan;
375
376 ATH_MSG_VERBOSE("(A.00) Looping over all collections for TMDB in the HIT container");
377 memset(pDigitSamplesArray, 0, sizeof(pDigitSamplesArray));
378
379 ATH_MSG_VERBOSE("(A.01) Going through collection ROS/DRAWER : "<< ros <<"/"<< drawer);
380 ATH_MSG_DEBUG(" Going through collection ROS/DRAWER : "<< ros <<"/"<< drawer);
381
382 if (m_cablingService->connected(ros, drawer)) {
383 ATH_MSG_VERBOSE("(A.02) ROS: "<< ros << " drawer: " << drawer << " is connected");
384 } else {
385 ATH_MSG_VERBOSE("(A.02) ROS: "<< ros << " drawer: " << drawer << " is NOT connected");
386 continue;
387 }
388
389 // Get drawer idhash for later access to the database to get ped and noise
390 //
391 m_tileHWID->get_hash(drawer_id, idhash, &drawer_context);
392
393 // **************************************************************
394 //
395 // Prepare buffer for MC Overlay procedure: pileup digits
396 //
397
398 memset(pDigitSamplesRndmArray, 0, sizeof(pDigitSamplesRndmArray));
399
400 if (m_rndmEvtOverlay && collItrRndm != lastCollRndm) {
401
402 const TileDigitsCollection *bkgDigitCollection(*collItrRndm);
403
404 if (hitCollection->identify() != bkgDigitCollection->identify()) {
405 ATH_MSG_ERROR ( "Frag IDs for hit collection and digits overlay collection do not match "
406 << MSG::hex << hitCollection->identify() << " != " << bkgDigitCollection->identify()
407 << MSG::dec );
408 return StatusCode::FAILURE;
409 }
410
411 ATH_MSG_DEBUG("Prepare buffer (digitsBuffer_rndm) for MC Overlay procdure: pileup digits");
412
413 for (const auto* bkgDigit : *bkgDigitCollection) {
414 bool good_channel = true;
415 /* Get digit HWIdentifier (= adc_id) */
416 HWIdentifier adc_id_rndm = (*bkgDigit).adc_HWID();
417 int channel = m_tileHWID->channel(adc_id_rndm);
418 ATH_MSG_VERBOSE ( "check channels from adc id in rndm container (TMDB channel): "<< channel );
419 /* Get digits */
420 digitsBuffer_rndm = (*bkgDigit).samples();
421 /* Get number of sample and compare with nSamples */
422 int nsamp_rndm = digitsBuffer_rndm.size();
423 if (nsamp_rndm != m_nSamples) {
424 digitsBuffer_rndm.resize(m_nSamples);
425 if (nsamp_rndm>0) {
426 for (int js=nsamp_rndm; js<m_nSamples; ++js) {
427 digitsBuffer_rndm[js] = digitsBuffer_rndm[js-1];
428 }
429 }
430 }
431 /* Fill the background digits array for the current channel and set a flag if any digit is NULL */
432 for (int j=0; j< m_nSamples;j++) {
433 pDigitSamplesRndmArray[channel][j] = digitsBuffer_rndm[j];
434 // If any digit is 0 something should be wrong so flag it in order to use during overlay the standard
435 // path to fill the expected background level for that channel
436 if (pDigitSamplesRndmArray[channel][j]==0) good_channel = false;
437 }
438 good_bkg[channel] = good_channel;
439
440 if (msgLvl(MSG::VERBOSE)){
441 msg(MSG::VERBOSE) << " Digits from pileup background " << channel << " " << ros << " " << drawer << " " << m_tileHWID->to_string(adc_id_rndm)<<" | ";
442 for (int j=0; j< (int) digitsBuffer_rndm.size(); j++) msg(MSG::VERBOSE) << digitsBuffer_rndm[j] <<" | ";
443 msg(MSG::VERBOSE) << "---> | ";
444 for (int j=0; j< (int) digitsBuffer_rndm.size(); j++) msg(MSG::VERBOSE) << pDigitSamplesRndmArray[channel][j] << " | ";
445 msg(MSG::VERBOSE) << endmsg;
446 }
447 }
448 ++collItrRndm; // skip to next digi collection
449 }
450
452 // (a.1) Iterate over all hits in a collection : access 'channel'
453 //
454
455 if ( hitCollection->empty() ) ATH_MSG_DEBUG("-- No hits in this drawer! Filling channels with either noise and pedestal or MC pileup overlay. --");
456
457 for (const TileHit* tile_hit : *hitCollection) {
458
459 // Get the pmt ID
460 //
461 Identifier pmt_id = tile_hit->pmt_ID();
462
463 // keep only D-cells and in addition cell BC8
464 //
465 int tower = m_tileID->tower(pmt_id);
466 int sample = m_tileID->sample(pmt_id);
467 if ( ! ((sample == TileID::SAMP_D) || (sample == TileID::SAMP_BC && tower == 7)) ) continue;
468
469 ATH_MSG_VERBOSE("(B.00) ++ Iterate over all the D layer channels with hits");
470
471 // In COOL database data will be organized acoording to TMDB channel (TMDBchan): 0..n with n=5 in EB and n=8 in LB
472 int TMDBchan;
473 // In here we need to access the real TILE HW channel (TILEchan) that it has a correspondance with TMDB chan given by EBchan and LBNchan
474 int TILEchan;
475
476 if (eb_ros) {
477 // cells D5, D6 and then D4 at the end
478 if (m_tileID->side(pmt_id) > 0)
479 TMDBchan = 1 - m_tileID->pmt(pmt_id) + ((tower>9) ? (tower - 10) : 4);
480 else
481 TMDBchan = m_tileID->pmt(pmt_id) + ((tower>9) ? (tower - 10) : 4);
482
483 TILEchan=EBchan[TMDBchan];
484 } else {
485 // Barrel (extension for HL-LHC)
486 if (tower == 0) {
487 TMDBchan = 0; // cell D0, channel 0 always
488 } else {
489 // cells D1. D2, D3 and BC8
490 if (m_tileID->side(pmt_id) > 0)
491 TMDBchan = 1 - m_tileID->pmt(pmt_id) + ((tower<7) ? (tower-1) : 7);
492 else
493 TMDBchan = m_tileID->pmt(pmt_id) + ((tower<7) ? (tower-1) : 7);
494 }
495
496 TILEchan=LBchan[TMDBchan];
497 }
498
499 double* pDigitSamples = pDigitSamplesArray[TMDBchan];
500
501 if (msgLvl(MSG::VERBOSE)){
502 HWIdentifier adc_id = m_tileHWID->adc_id(drawer_id, TMDBchan, TileID::LOWGAIN);
503
504 ATH_MSG_VERBOSE( "(B.01) Correct pmt being transported in XXchan[]: "<<TMDBchan<<" "<<TILEchan<< "=?"
505 << m_tileHWID->channel(m_cablingService->s2h_channel_id(pmt_id))
506 << " For reference get TMDB adc_id: " << m_tileHWID->to_string(adc_id) );
507 ATH_MSG_VERBOSE( "(B.02) New hit in ROS/DRAWER/PMT "<<ros<<"/"<<drawer<<"/"<<TMDBchan<<" ("<<TILEchan<<")"
508 << " pmt_id "<< m_tileID->to_string(pmt_id,-1)
509 << " adc_id "<< m_tileHWID->to_string(adc_id) );
510 }
511
512 // Scintillator Energy -> Cell Energy (uses sampling fraction)
513 //
514 int channel = m_tileHWID->channel(m_cablingService->s2h_channel_id(pmt_id));
515 double hit_calib = samplingFraction->getSamplingFraction(drawerIdx, channel);
516 hit_calib = std::round(hit_calib * 1000) / 1000;
517
518 ATH_MSG_VERBOSE("------ Sampling fraction: " << hit_calib);
519
521 // (a.2) Loop over the hits of this channel
522 // Calibrations are applied per subhit and energy added per subhit of a channel
523 //
524
525 int n_hits = tile_hit->size();
526
527 ATH_MSG_VERBOSE("------ Number of hits in channel: " << n_hits);
528
529 for (int ihit = 0; ihit < n_hits; ++ihit) {
530
531 ATH_MSG_VERBOSE("(C.00) ++ Iterating over the hits of channel " << TILEchan <<": hit " << ihit <<"/"<< n_hits);
532
533 double e_hit = tile_hit->energy(ihit); // [MeV] energy deposited in scintillator
534 double e_pmt = e_hit * hit_calib; // [MeV] true cell energy
535
536 ATH_MSG_VERBOSE("(C.01) Energy in scintillator [MeV]: " << e_hit << " true cell energy [MeV]: " << e_pmt);
537
538 double t_hit = tile_hit->time(ihit);
539
540 ATH_MSG_VERBOSE("(C.02.01) Phase " << t_hit);
541
542 // Load pulse
543 //
544 int k = 0;
545 float phase = 0.0;
546 float y = 0.0;
547 float dy = 0.0;
548 double shape = 0.0;
549
550 int ishift = (int) (t_hit / m_timeStep + 0.5);
551
552 ATH_MSG_VERBOSE( "(C.02.02) ishift :" << t_hit << "/" << m_timeStep << "+0.5 = " << ishift);
553
555 for (int js = 0; js < m_nSamples; ++js) {
556 k = m_binTime0 + (js - m_iTrig) * m_nBinsPerX - ishift;
557 if (k < 0) k = 0;
558 else if (k > m_nShape) k = m_nShape;
559
560 ATH_MSG_VERBOSE( "(C.02.03) k : " << m_binTime0 << "+(" << js << "-" << m_iTrig << ")*" << m_nBinsPerX << "-" << ishift << " = " << k);
561
562 phase = (k - m_binTime0) * m_timeStep;
563
564 ATH_MSG_VERBOSE( "(C.02.04) phase : " << k << "-" << m_binTime0 << "*" << m_timeStep << " = " << phase);
565
566 pulse->getPulseShapeYDY(drawerIdx, TMDBchan, TileID::LOWGAIN, phase, y, dy);
567 shape = (double) y;
568 pDigitSamples[js] += e_pmt * shape; // MeV
569
570 ATH_MSG_VERBOSE( "(C.03.0) Sample no.= " << js
571 << " idx= " << k
572 << " Shape wt. = " << shape
573 << " Amp = " << pDigitSamples[js] << " [MeV]");
574 } //END loop over samples
575 } else {
576 for (int js = 0; js < m_nSamples; ++js) {
577 k = m_binTime0 + (js - m_iTrig) * m_nBinsPerX - ishift;
578 if (k < 0) k = 0;
579 else if (k > m_nShape) k = m_nShape;
580
581 ATH_MSG_VERBOSE( "(C.02.03) k : " << m_binTime0 << "+(" << js << "-" << m_iTrig << ")*" << m_nBinsPerX << "-" << ishift << " = " << k);
582
583 pDigitSamples[js] += e_pmt * m_shapeMuonReceiver[k]; // MeV
584
585 ATH_MSG_VERBOSE( "(C.03.0) Sample no.= " << js
586 << " idx= " << k
587 << " Shape wt. = " << m_shapeMuonReceiver[k]
588 << " Amp = " << pDigitSamples[js]
589 << "[MeV] Energy: " << e_pmt << " LOGAIN from TileInfo");
590 } //END loop over samples
591 } // END if (m_useCoolPulseShapes)
592 } // END loop over sub-HITS
593
594 ATH_MSG_VERBOSE("++ ENDED Loop over hits for a channel");
595 ATH_MSG_DEBUG("(C.04) Went over " << n_hits << " hits for channel"
596 << m_tileHWID->to_string(drawer_id,-2) << "/" << TMDBchan << " (" << TILEchan << ")"
597 << " digits [MeV] "<< pDigitSamples[0]
598 << "/" << pDigitSamples[1]
599 << "/" << pDigitSamples[2]
600 << "/" << pDigitSamples[3]
601 << "/" << pDigitSamples[4]
602 << "/" << pDigitSamples[5]
603 << "/" << pDigitSamples[6]);
604 ATH_MSG_VERBOSE("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
605 } // END loop over a HIT collection
606
607 ATH_MSG_VERBOSE("++ END loop over a HIT collection");
608
610 // (a.3) The pulse has a shape and a amplitude in MeV now it is converted into ADC
611 // counts and either add NOISE and PEDESTAL or the OVERLAY digits
612 //
613 // PEDESTAL [ADC counts] and NOISE [ADC counts] as stored in Tile
614 // Conditions (FIXED values but also flag for collection from COOL)
615 //
616 // Keep containers for each module (each partition) the same size
617 // between events i.e. ALL channels are filled even with ZERO energy
618 //
619
620 ATH_MSG_VERBOSE("++ START filling of channels with background either noise+pedestal or overlay");
621
622 for (int TMDBchan = 0; TMDBchan < upperLim; ++TMDBchan) {
623
624 double* pDigitSamples=pDigitSamplesArray[TMDBchan];
625 int TILEchan = (eb_ros) ? EBchan[TMDBchan] : LBchan[TMDBchan];
626
627 HWIdentifier adc_id = m_tileHWID->adc_id(drawer_id, TMDBchan, TileID::LOWGAIN);
628
629 ATH_MSG_DEBUG( "(D.) Going now to channel " << " TMDBchan: " << TMDBchan << " TILEchan: " << TILEchan);
630 ATH_MSG_DEBUG( "(D.00) Add noise and pedestal in "
631 << " TMDBchan: " << TMDBchan << " TILEchan: " << TILEchan
632 << " ROS: " << ros
633 << " drawer: " << drawer
634 << " drawer idx: " << drawerIdx
635 << " drawer_id: " << m_tileHWID->to_string(drawer_id,-2)
636 << " channel: " << m_tileHWID->to_string(adc_id,-1));
637 // adc/pCb / MeV/pCb = adc/MeV
638 //
639 muRcv_Max = m_tileInfo->MuRcvMax(adc_id); // [adc]
640 muRcv_Calib = m_tileInfo->MuRcvCalib(adc_id); // pCb->[adc]
641 double mev2ADC_factor = muRcv_Calib / emScale->calibrateChannel(drawerIdx,TILEchan,TileID::LOWGAIN, 1.
644 ATH_MSG_VERBOSE( "(D.01) Channel: "<<ros<<'/'<<drawer<<'/'<< TMDBchan
645 << " adc/pCb: "<< muRcv_Calib
646 << " Mev/pCb: "<< emScale->calibrateChannel( drawerIdx,
647 TILEchan,
649 1.,
652 << " final calibration factor adc/MeV: "<< mev2ADC_factor);
653
654 ATH_MSG_VERBOSE( "(D.02) Pulse digits [MeV]:"
655 << " " << pDigitSamples[0]
656 << " " << pDigitSamples[1]
657 << " " << pDigitSamples[2]
658 << " " << pDigitSamples[3]
659 << " " << pDigitSamples[4]
660 << " " << pDigitSamples[5]
661 << " " << pDigitSamples[6]
662 << " [All ZERO if there is no hit in channel.] ");
663
664 if ( good_bkg[TMDBchan] ) {
665 // Collecting digits for MC Overlay procedure from overlay container
666 // IF good digits ere collected (no ZEROS <> good_bkg[TMDBchan]==true) then add the background to the simulated digits
667 // ELSE bad digits (any ZEROS <> good_bkg[TMDBchan]==false) then follow the standard path adding muRcv_Ped and muRvc_NoiseSigma
668
669 ATH_MSG_DEBUG("++ Adding to signal digits -- The MC PILE-UP OVERLAY digits " << m_rndmEvtOverlay << " " << m_integerDigits);
670
671 for (int js = 0; js < m_nSamples; ++js) {
672 // Signal
673 //
674 ATH_MSG_VERBOSE( "(D.02.0"<< js+1 <<") sample "<< js+1 <<" E_{Signal} [adc]: "<< pDigitSamples[js] * mev2ADC_factor <<" -- Overlay");
675 digitsBuffer[js] = pDigitSamples[js] * mev2ADC_factor;
676 // Pileup
677 //
678 ATH_MSG_VERBOSE( "(D.02.0"<< js+1 <<") sample "<< js+1 <<" E_{PileUp} [adc]: "<< pDigitSamplesRndmArray[TMDBchan][js] <<" -- Overlay");
679 digitsBuffer[js] += pDigitSamplesRndmArray[TMDBchan][js];
680 // Simulated pulse above allowed maximum
681 //
682 if (digitsBuffer[js] > muRcv_Max) digitsBuffer[js] = muRcv_Max;
683 // Rounding the ADC counts
684 //
685 if (m_integerDigits) digitsBuffer[js] = round(digitsBuffer[js]);
686 ATH_MSG_VERBOSE( "(D.02.0"<< js+1 <<") sample "<< js+1 <<" calibration [adc/MeV] "<< mev2ADC_factor <<"-> E_{Signal+PileUp} [adc]: "<< digitsBuffer[js] <<" -- Overlay");
687 }
688 } else {
689 if (m_rndmEvtOverlay) ATH_MSG_INFO("At least one digit is zero in background file using the stadart path to fill pedestal and noise in digits");
690 // Different for each channel_id might be the case in the future (now a const. in TileInfoLoader.cxx)
691 //
692 muRcv_NoiseSigma = m_tileInfo->MuRcvNoiseSigma(adc_id); // [adc]
693 muRcv_Ped = m_tileInfo->MuRcvPed(adc_id); // [adc]
694
695 ATH_MSG_VERBOSE( "(D.03) Tile Muon Receiver parameters:"
696 << " noi " << muRcv_NoiseSigma
697 << " ped " << muRcv_Ped
698 << " cal " << muRcv_Calib
699 << " max " << muRcv_Max);
700
701 // Collecting digits for standard procedure NO OVERLAY: pedestal+noise
702 // ADD digitsBuffer[m_nSamples] WITH Ped and Noise from COOLDB/ATHENA
703 //
704 ATH_MSG_DEBUG("++ Adding to signal digits -- The PEDESTAL + NOISE digits "<< m_tilePedestal <<" "<< m_tileNoise << " " << m_integerDigits);
705 // Collecting pedestal from the database
706 //
707 if (m_tilePedestal) {
708 pedSim = sampleNoise->getPed(idhash, TMDBchan, TileID::LOWGAIN);
709 // As in TileDigitsMaker bug fix for wrong ped value in DB
710 //
711 if (pedSim == 0.0) pedSim = 30.;
712 } else {
713 pedSim = muRcv_Ped;
714 }
715 // Collecting noise from the database
716 //
717 if (m_tileNoise) {
718 // Generate an array to randomize the noise for each digit
719 //
720 RandGaussQ::shootArray(rndmEngine, m_nSamples, Rndm, 0.0, 1.0);
721 RandFlat::shootArray(rndmEngine, 1, Rndm_dG, 0.0, 1.0);
722 sigma_Hfn1 = sampleNoise->getHfn1(idhash, TMDBchan, TileID::LOWGAIN);
723 sigma_Hfn2 = sampleNoise->getHfn2(idhash, TMDBchan, TileID::LOWGAIN);
724 if (sigma_Hfn1 > 0 || sigma_Hfn2) {
725 sigma_Norm = sigma_Hfn1 / (sigma_Hfn1 + sigma_Hfn2 * sampleNoise->getHfnNorm(idhash, TMDBchan, TileID::LOWGAIN));
726 } else {
727 sigma_Hfn1 = sampleNoise->getHfn(idhash, TMDBchan, TileID::LOWGAIN);
728 sigma_Norm = 1.;
729 }
730 if (Rndm_dG[0] < sigma_Norm) sigmaSim = sigma_Hfn1;
731 else sigmaSim = sigma_Hfn2;
732 } else {
733 sigmaSim = muRcv_NoiseSigma;
734 }
735 // Loop over samples and either use noise and ped from db or user location (TileInfoLoader.cxx)
736 //
737 for (int js = 0; js < m_nSamples; ++js) {
738 // Signal
739 //
740 ATH_MSG_VERBOSE( "(D.02.0"<< js+1 <<") sample "<< js+1 <<" E [MeV]: "<< pDigitSamples[js]);
741 digitsBuffer[js] = pDigitSamples[js] * mev2ADC_factor;
742 ATH_MSG_VERBOSE( "(D.02.0"<< js+1 <<") sample "<< js+1 <<" calibration [adc/MeV] "<< mev2ADC_factor <<"-> E [adc]: "<< digitsBuffer[js]);
743 // Pedestal (amp)
744 //
745 digitsBuffer[js] += pedSim;
746 ATH_MSG_VERBOSE( "(D.02.0"<< js+1 <<") sample "<< js+1 <<" adding pedestal "<< pedSim <<"-> E [adc]: "<< digitsBuffer[js]);
747 // Noise (rms)
748 //
749 if (m_tileNoise) {
750 digitsBuffer[js] += sigmaSim * Rndm[js];
751 ATH_MSG_VERBOSE( "(D.02.0"<< js+1 <<") sample "<< js+1 <<" adding noise "<< sigmaSim * Rndm[js] <<"-> E [adc]: "<< digitsBuffer[js]);
752 }
753 // Simulated pulse above allowed maximum
754 //
755 if (digitsBuffer[js] > muRcv_Max) digitsBuffer[js] = muRcv_Max;
756 // Rounding the ADC counts
757 //
758 if (m_integerDigits) digitsBuffer[js] = round(digitsBuffer[js]);
759 }
760 }
761
762 // If channel is good, create TileDigits object and store in container.
763 //
764 bool chanIsBad = false;
765
766 if (m_maskBadChannels) {
767 TileBchStatus status = badChannels->getAdcStatus( m_tileHWID->adc_id(drawer_id, TILEchan, TileID::LOWGAIN) );
768 chanIsBad = status.isBad();
769 }
770
771 if (chanIsBad) {
772 for (int js = 0; js < m_nSamples; ++js) {
773 digitsBuffer[js] = 255;// in TMDB we have 8-bit ADCs
774 }
775 ATH_MSG_VERBOSE( "(D.03) Masking Channel: "<< ros << '/' << drawer << '/' << TILEchan <<" ("<< TMDBchan <<") LowGain" );
776 } else {
777 ATH_MSG_VERBOSE( "(D.03) Good Channel : "<< ros << '/' << drawer << '/' << TILEchan <<" ("<< TMDBchan <<") LowGain" );
778 }
779
780 ATH_MSG_VERBOSE( "++ Changed to TMDB adc_id: " << m_tileHWID->to_string(adc_id) << " and save a TileDigits object into a container." );
781 std::unique_ptr<TileDigits> muonReceiverDigits = std::make_unique<TileDigits>(adc_id, digitsBuffer);
782 ATH_MSG_VERBOSE( "++ Create a TileRawChannelObject object and set it into a container " );
783 TileRawChannel* muRcvRawChannel = m_MuRcvBuildTool->rawChannel(muonReceiverDigits.get(), ctx);
784 ATH_CHECK( muRcvDigitsContainer->push_back(std::move(muonReceiverDigits)) );
785 ATH_CHECK( muRcvRawChannelContainer->push_back(muRcvRawChannel) );
786 if (msgLvl(MSG::DEBUG)){
787 ATH_MSG_DEBUG( "++ Channel " << m_tileHWID->to_string(adc_id,-1)
788 << " Digitized pulse [ADC] "<< digitsBuffer[0]
789 << "/" << digitsBuffer[1]
790 << "/" << digitsBuffer[2]
791 << "/" << digitsBuffer[3]
792 << "/" << digitsBuffer[4]
793 << "/" << digitsBuffer[5]
794 << "/" << digitsBuffer[6] );
795 ATH_MSG_DEBUG( "++ Raw channel reconstruction Ch: "<< m_tileHWID->to_string(adc_id,-1)
796 <<" E [ADC]: "<< muRcvRawChannel->amplitude()
797 <<" Time [ns]: "<< muRcvRawChannel->time()
798 <<" Qf: "<< muRcvRawChannel->quality() );
799 }
800 }
801 } // END loop over all HIT collections in container
802 if (msgLvl(MSG::VERBOSE)) muRcvDigitsContainer->print();
803
805 // (a.4) Register the digits container in the TES
806 //
807
808 ATH_MSG_VERBOSE ( "(A.05) Send to event store all collected objects " );
809
811 ATH_CHECK( muRcvDigitsCnt.record(std::move(muRcvDigitsContainer)) );
812
814 ATH_CHECK( muRcvRawChannelCnt.record(std::move(muRcvRawChannelContainer)) );
815
816 ATH_MSG_VERBOSE( "TilePulseForTileMuonReceiver execution completed" );
817
818 return StatusCode::SUCCESS;
819}
820
821// finalize
822//
824 ATH_MSG_VERBOSE("Finalizing TilePulseForTileMuonReceiver");
825
826 ATH_MSG_INFO("TilePulseForTileMuonReceiver finalized successfully");
827 return StatusCode::SUCCESS;
828}
#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_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Helpers for checking error return status codes and reporting errors.
Handle class for reading from StoreGate.
Handle class for recording to StoreGate.
#define nLBchan
#define nEBchan
Helper for holding non-const raw data prior to recording in SG.
Helper for holding non-const raw data prior to recording in SG.
#define y
A wrapper class for event-slot-local random engines.
Definition RNGWrapper.h:56
void setSeed(const std::string &algName, const EventContext &ctx)
Set the random seed using a string (e.g.
Definition RNGWrapper.h:154
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition RNGWrapper.h:108
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor with parameters:
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
MsgStream & msg() const
This class saves the "context" of an expanded identifier (ExpandedIdentifier) for compact or hash ver...
Definition IdContext.h:26
This is a "hash" representation of an Identifier.
const_pointer_type retrieve()
virtual bool isValid() override final
Can the handle be successfully dereferenced?
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
Condition object to keep Tile channel and ADC status.
const TileBchStatus & getAdcStatus(const HWIdentifier adc_id) const
Return Tile ADC status.
Class holding bad channel problems.
static unsigned int getDrawerIdx(unsigned int ros, unsigned int drawer)
Returns a drawer hash.
@ EXTBAR_NEG
Definition TileHWID.h:71
@ EXTBAR_POS
Definition TileHWID.h:70
ServiceHandle< TileCablingSvc > m_cablingSvc
Name of Tile cabling service.
SG::WriteHandleKey< TileDigitsContainer > m_muRcvDigitsContainerKey
int m_iTrig
Index of the triggering time slice.
SG::ReadHandleKey< TileHitContainer > m_hitContainerKey
double m_tileThresh
Actual threshold value.
ServiceHandle< PileUpMergeSvc > m_mergeSvc
double m_timeStep
Time step in pulse shape: 25.0 / nBinsPerX.
SG::ReadCondHandleKey< TilePulse > m_pulseShapeKey
Name of TilePulseShape in condition store.
ServiceHandle< IAthRNGSvc > m_rndmSvc
Random number service to use.
int m_nShape
Number of bins in pulse shape.
Gaudi::Property< std::string > m_infoName
const TileCablingService * m_cablingService
TileCabling instance.
SG::WriteHandleKey< TileRawChannelContainer > m_muRcvRawChannelContainerKey
virtual StatusCode initialize() override
initialize method
virtual StatusCode execute() override
execute method
int m_binTime0
Index of time=0 bin for pulse shape.
ToolHandle< TileRawChannelBuilderMF > m_MuRcvBuildTool
TilePulseForTileMuonReceiver(const std::string &name, ISvcLocator *pSvcLocator)
SG::ReadCondHandleKey< TileBadChannels > m_badChannelsKey
Name of TileBadChannels in condition store.
SG::ReadCondHandleKey< TileEMScale > m_emScaleKey
Name of TileEMScale in condition store.
int m_nBinsPerX
Number of bins per bunch crossing in pulse shape.
Gaudi::Property< std::string > m_randomStreamName
Random Stream Name.
int m_nSamples
Number of time slices for each channel.
SG::ReadHandleKey< TileDigitsContainer > m_inputDigitContainerKey
SG::ReadCondHandleKey< TileSamplingFraction > m_samplingFractionKey
Name of TileSamplingFraction in condition store.
SG::ReadCondHandleKey< TileSampleNoise > m_sampleNoiseKey
Name of TileSampleNoise in condition store.
virtual StatusCode finalize() override
finalize method
std::vector< double > m_shapeMuonReceiver
Muon receiver pulse shape.
Condition object to keep and provide Tile pulse shape.
Definition TilePulse.h:15
bool getPulseShapeYDY(unsigned int drawerIdx, unsigned int channel, unsigned int adc, float time, float &y, float &dy) const
Definition TilePulse.h:35
float time(int ind=0) const
float quality(int ind=0) const
float amplitude(int ind=0) const
Condition object to keep and provide Tile sample noise.
float getPed(unsigned int drawerIdx, unsigned int channel, unsigned int adc) const
float getHfn2(unsigned int drawerIdx, unsigned int channel, unsigned int adc) const
float getHfn1(unsigned int drawerIdx, unsigned int channel, unsigned int adc) const
float getHfn(unsigned int drawerIdx, unsigned int channel, unsigned int adc) const
float getHfnNorm(unsigned int drawerIdx, unsigned int channel, unsigned int adc) const
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
std::list< value_t > type
type of the collection of timed data object