ATLAS Offline Software
Loading...
Searching...
No Matches
Run2TriggerTowerMaker.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5// ================================================
6// Run2TriggerTowerMaker class Implementation
7// ================================================
8
10
11// trigger include(s)
17
19
22
23// calorimeter include(s)
26
29
30//For getting TriggerTowers from BS
32
33// For the Athena-based random numbers.
37#include "GaudiKernel/IIncidentSvc.h"
38
39// AthenaMT
42
43#include "CLHEP/Random/RandGaussZiggurat.h"
44#include "CLHEP/Random/Randomize.h"
45#include "CLHEP/Random/RandomEngine.h"
46
47#include <cassert>
48#include <cmath>
49#include <fstream>
50#include <limits> // for std::numeric_limits<std::streamsize>
51#include <utility> // for std::move
52#include <stdexcept>
53#include <sys/types.h>
54#include <unordered_map>
55
56#include <iostream>
57using std::cout;
58using std::endl;
59
60namespace {
61 template <typename MSG, typename T>
62 void printVec(MSG& msg, const std::vector<T>& v) {
63 for(auto x : v) msg << (int)x << endmsg;
64 }
65
66 template <typename MSG, typename T, std::size_t N>
67 void printVec(MSG& msg, const std::array<T, N>& v) {
68 for(auto x : v) msg << (int)x << endmsg;
69 }
70
71 constexpr static int ADCMAX = 1023;
72 constexpr static int SATURATIONVALUE = 255;
73
74 // keep these local to this compilation unit
75 static const xAOD::TriggerTower::Decorator<int> firDecorator("fir");
76} // namespace
77
78namespace LVL1 {
79
80 Run2TriggerTowerMaker::Run2TriggerTowerMaker(const std::string& name, ISvcLocator* pSvcLocator)
81 : AthAlgorithm(name, pSvcLocator),
82 m_rngSvc("AthRNGSvc", name),
83 m_rndmADCs(0),
84 m_mappingTool("LVL1::PpmMappingTool/PpmMappingTool", this),
85 m_bstowertool("LVL1BS__TrigT1CaloDataAccessV2/TrigT1CaloDataAccessV2", this),
86 m_caloId(0),
87 m_cpLutScale(1.),
88 m_jepLutScale(1.),
89 m_TileToMeV(s_MEV/4.1), // Scale for converting ET -> counts
90 m_TileTTL1Ped(0.), // TileTTL1 pedestal value - need to subtract if set non-zero
92 m_doOverlay(false), m_isReco(false)
93 {
94 declareProperty("RngSvc", m_rngSvc, "Random number service");
95 declareProperty("DigiEngine", m_digiEngine = "TrigT1CaloSim_Digitization");
96
97 declareProperty("L1TriggerTowerTool", m_TTtool);
98 declareProperty("PpmMappingTool", m_mappingTool);
99
101 declareProperty("EmTTL1ContainerName",m_EmTTL1ContainerName= "LArTTL1EM");
102 declareProperty("HadTTL1ContainerName",m_HadTTL1ContainerName= "LArTTL1HAD");
103 declareProperty("TileTTL1ContainerName",m_TileTTL1ContainerName= "TileTTL1Cnt");
104 declareProperty("RequireAllCalos",m_requireAllCalos=true,"Should EM,Had and Tile all be available?");
105
108 declareProperty("CellType", m_cellType = TTL1);
109
110 // ADC simulation
111 declareProperty("ADCStep", m_adcStep=250.);
112 declareProperty("ADCNoise", m_adcVar=0.65);
113 declareProperty("CalibrationUncertainty", m_gainCorr=0.);
114
115 declareProperty("DoOverlay",m_doOverlay = false);
116 declareProperty("IsReco",m_isReco = false);
117
118 declareProperty("DecorateFIR", m_decorateFIR = false, "Add FIR values to the xAOD::TriggerTowers");
119
120 declareProperty("ZeroSuppress", m_ZeroSuppress = true, "Do not save towers with 0 energy");
121
122 declareProperty("ChanCalibFolderKeyoverlay",m_chanCalibKeyoverlay = "/TRIGGER/L1Calo/V2overlay/Calibration/Physics/PprChanCalib","PprChanCalib key for overlay");
123 declareProperty("ChanDefaultsFolderKeyoverlay",m_chanDefaultsKeyoverlay = "/TRIGGER/L1Calo/V2overlay/Configuration/PprChanDefaults","PprChanDefaults key for overlay");
124 declareProperty("DisabledTowersFolderKeyoverlay",m_disabledTowersKeyoverlay = "/TRIGGER/L1Calo/V2overlay/Conditions/DisabledTowers","DisabledTowers key for overlay");
125 declareProperty("DeadChannelsFolderKeyoverlay",m_deadChannelsKeyoverlay = "/TRIGGER/L1Calo/V2overlay/Calibration/PpmDeadChannels","PpmDeadChannels key for overlay");
126
127 // Create hash table for E->ET conversions
128 /* Fill table with dummy values */
129 m_sinThetaHash.fill(-1.);
130
131 /* set values for barrel region with granularity of 0.1*/
132 for(unsigned int i = 0; i < 25; i++) {
133 m_sinThetaHash[i] = 1.0/cosh((i+0.5)* 0.1);
134 }
135
136 /* set values for EndCap with granularity of 0.2 except tt by |3.2|
137 eta values are are: 2.6, 2.8, 3.0, 3.15 */
138 m_sinThetaHash[26] = 1.0/cosh(2.6);
139 m_sinThetaHash[28] = 1.0/cosh(2.8);
140 m_sinThetaHash[30] = 1.0/cosh(3.0);
141 m_sinThetaHash[31] = 1.0/cosh(3.15);
142
143 /* fcal granularity is 0.425 */
144 m_sinThetaHash[ (unsigned int)(32 + (0.5*0.425)*10.) ] = 1.0/cosh(3.2 + 0.5*0.425);
145 m_sinThetaHash[ (unsigned int)(32 + (1.5*0.425)*10.) ] = 1.0/cosh(3.2 + 1.5*0.425);
146 m_sinThetaHash[ (unsigned int)(32 + (2.5*0.425)*10.) ] = 1.0/cosh(3.2 + 2.5*0.425);
147 m_sinThetaHash[ (unsigned int)(32 + (3.5*0.425)*10.) ] = 1.0/cosh(3.2 + 3.5*0.425);
148 }
149
151
153 {
154 ATH_MSG_DEBUG("Initialising");
155
156 ATH_CHECK(detStore()->retrieve(m_caloId));
157 ATH_CHECK(m_mappingTool.retrieve());
158 ATH_CHECK(m_TTtool.retrieve());
159 ATH_CHECK(m_rngSvc.retrieve());
160 ATH_CHECK(m_bstowertool.retrieve());
161
162 m_rndmADCs = m_rngSvc->getEngine(this, m_digiEngine);
163 if(!m_rndmADCs) {
164 ATH_MSG_ERROR("Failed to retrieve random engine");
165 return StatusCode::FAILURE;
166 }
167
168 // Listen for BeginRun
169 ServiceHandle<IIncidentSvc> incSvc("IncidentSvc",name());
170 ATH_CHECK(incSvc.retrieve());
171 incSvc->addListener(this, "BeginRun");
172
173 // reserve enough storage for the amps
174 m_xaodTowersAmps.assign(7168, std::vector<double>());
175
176 ATH_CHECK(m_xaodevtKey.initialize());
177 ATH_CHECK(m_actMuKey.initialize());
178
179 ATH_CHECK(m_inputTTLocation.initialize());
180
181 ATH_CHECK(m_EmTTL1ContainerName.initialize());
182 ATH_CHECK(m_HadTTL1ContainerName.initialize());
184 ATH_CHECK(m_outputLocation.initialize());
185
186 ATH_CHECK(m_outputLocationRerun.initialize());
187
188 //Rerun on trigger towers
189 if (m_cellType == TRIGGERTOWERS) {
194 }
195 //Start from RDO inputs
196 else if (m_cellType == TTL1) {
199 }
200
201 ATH_CHECK( m_L1MenuKey.initialize() );
202 ATH_CHECK( m_chanCalibKey.initialize() );
203 ATH_CHECK( m_chanDefaultsKey.initialize() );
204 ATH_CHECK( m_disabledTowersKey.initialize() );
205 ATH_CHECK( m_deadChannelsKey.initialize() );
206
207 return StatusCode::SUCCESS;
208 }
209
212 void Run2TriggerTowerMaker::handle(const Incident& inc)
213 {
214 if(inc.type() != "BeginRun") return;
216
217 auto l1Menu = SG::makeHandle( m_L1MenuKey );
218 try {
219 m_cpLutScale = l1Menu->thrExtraInfo().EM().emScale();
220 m_jepLutScale = l1Menu->thrExtraInfo().JET().jetScale();
221 } catch(const std::out_of_range&) {
222 ATH_MSG_DEBUG("No Legacy triggers in menu, using default scales");
223 m_cpLutScale = 2;
224 m_jepLutScale = 1;
225 }
226
227 ATH_MSG_INFO("REGTEST CP scale = " << m_cpLutScale << " count/GeV");
228 ATH_MSG_INFO("REGTEST JEP scale = " << m_jepLutScale << " count/GeV");
229
232
233
234
235
236 if (m_doOverlay) {
237
238 throw std::runtime_error("Overlay no longer supported in Run2TriggerTowerMaker");
239
240 // Leaving this code commented here as a reminder of what functionality might need to be added to L1CaloCondAlg
241 // if we want to restart supporting overlay
242
243// if (! m_condSvc->retrieve(m_chanCalibContaineroverlay, m_chanCalibKeyoverlay).isSuccess()){ATH_MSG_ERROR("failed!");}
244// ATH_MSG_INFO("Loading "<<m_chanCalibKeyoverlay<<" into m_chanCalibContaineroverlay");
245// if (! m_condSvc->retrieve(m_disabledTowersContaineroverlay, m_disabledTowersKeyoverlay).isSuccess()){ATH_MSG_ERROR("failed!");}
246// if (! m_condSvc->retrieve(m_deadChannelsContaineroverlay, m_deadChannelsKeyoverlay).isSuccess()){ATH_MSG_ERROR("failed!");}
247// L1CaloPprChanDefaultsContainer *cDCoverlay = nullptr;
248// if (! m_condSvc->retrieve(cDCoverlay, m_chanDefaultsKeyoverlay).isSuccess()){ATH_MSG_ERROR("failed!");}
249// if(!m_chanCalibContaineroverlay || !cDCoverlay ||
250// !m_disabledTowersContaineroverlay || !m_deadChannelsContaineroverlay) {
251// ATH_MSG_ERROR("Could not retrieve database containers for overlay. Aborting ...");
252// throw std::runtime_error("Run2TriggerTowerMaker: database container for overlay not accesible");
253// }
254//
255// auto* defaultsoverlay = cDCoverlay->pprChanDefaults(0); // non-owning ptr
256// if(!defaultsoverlay) {
257// ATH_MSG_ERROR("Could not retrieve channel 0 PprChanDefaults folder for overlay. Aborting ...");
258// throw std::runtime_error("Run2TriggerTowerMaker: channel 0 of PprChanDefaults for overlay not accesible");
259// }
260// m_chanDefaultsoverlay = *defaultsoverlay;
261
262 }
263
264 const TileInfo* tileInfo = nullptr;
265 if(detStore()->retrieve(tileInfo, "TileInfo").isFailure()) {
266 ATH_MSG_ERROR("Failed to find TileInfo");
267 m_TileToMeV = s_MEV/4.1;
268 }
269
270 m_TileToMeV = s_MEV/tileInfo->TTL1Calib({});
271 ATH_MSG_DEBUG("Tile TTL1 calibration scale = " << tileInfo->TTL1Calib({}));
272 m_TileTTL1Ped = tileInfo->TTL1Ped({});
273 ATH_MSG_DEBUG("Tile TTL1 pedestal value = " << m_TileTTL1Ped);
274
275 // try to determine wheter we run on data or on simulation
276 const xAOD::EventInfo* evtinfo{nullptr};
277 if(evtStore()->retrieve(evtinfo)!=StatusCode::SUCCESS) {
278 ATH_MSG_WARNING("Could not determine if input file is data or simulation. Will assume simulation.");
279 }
280 else {
281 bool isData = !(evtinfo->eventTypeBitmask()&xAOD::EventInfo::IS_SIMULATION);
282 m_isDataReprocessing = isData;
284 ATH_MSG_INFO("Detected data reprocessing. Will take pedestal correction values from input trigger towers.");
285 } else {
286 ATH_MSG_VERBOSE("No data reprocessing - running normal simulation.");
287 }
288 }
289
290 // If this is an overlay job, we will handle this in a different way
291 if (m_doOverlay) {
292 m_isDataReprocessing = false;
293 ATH_MSG_INFO("L1Calo overlay job - setting m_isDataReprocessing to false");
294 }
295
296
297 }
298
300 ATH_MSG_DEBUG("Finalizing");
301 return StatusCode::SUCCESS;
302 }
303
307 StatusCode Run2TriggerTowerMaker::execute(const EventContext& ctx) {
308 ATH_MSG_VERBOSE("Executing");
309
310 if (m_isReco && m_doOverlay) return StatusCode::SUCCESS; // nothing to to, since we did overlay and made towers during digi
311
312
313 // retrieve conditions
315 CHECK(pprCalibCont.isValid());
316 m_chanCalibContainer = (*pprCalibCont);
318 CHECK(pprDisabledTowers.isValid());
319 m_disabledTowersContainer = (*pprDisabledTowers);
321 CHECK(pprDeadTowers.isValid());
322 m_deadChannelsContainer = (*pprDeadTowers);
324 CHECK(pprChanDefaults.isValid());
325 auto* defaults = pprChanDefaults->pprChanDefaults(0); // non-owning ptr
326 if(!defaults) {
327 ATH_MSG_ERROR("Could not retrieve channel 0 PprChanDefaults folder. Aborting ...");
328 throw std::runtime_error("Run2TriggerTowerMaker: channel 0 of PprChanDefaults not accesible");
329 }
331
332 m_rndmADCs->setSeed (m_digiEngine, ctx);
333
336 m_xaodTowers->setStore(m_xaodTowersAux.get());
337 m_xaodTowers->resize(7168); // avoid frequent reallocations
338 m_curIndex = 0u;
339
340 switch(m_cellType) {
341 case TRIGGERTOWERS:
342 ATH_MSG_VERBOSE("Looking for TriggerTower input");
344 break;
345 case TTL1:
346 ATH_MSG_VERBOSE("Looking for calo towers");
348 digitize(ctx); // digitisation
349 break;
350 default:
351 ATH_MSG_ERROR("Unsupported Cell Type!!!!!!"); return StatusCode::FAILURE;
352 }
353
356 ATH_CHECK(evt.isValid());
357 ATH_CHECK(muDecor.isPresent());
358 const float mu = muDecor(0);
359
360 ATH_CHECK(preProcess(evt->bcid(), mu)); // FIR, BCID etc
361
362 if (m_doOverlay) {
363 ATH_CHECK( addOverlay(evt->bcid(), mu) );
364 }
365
366 // store them thar trigger towers
367 ATH_CHECK(store());
368
369 return StatusCode::SUCCESS;
370 }
371
374 {
375 if (!db) return false; // No DB entry - assume that this is not a dead channel
376 if (db->errorCode() > 0 || db->noiseCut() > 0) return true; // We do not want these
377 return false;
378 }
379
381 {
382 if (!db) return false; // No DB entry - assume that this is not a disabled channel
383 if (db->disabledBits() > 0) return true; // We do not want these
384 return false;
385 }
386
388 {
389 bool isDead = IsDeadChannel(dead->ppmDeadChannels(tt->coolId()));
390 bool isDisabled = IsDisabledChannel(disabled->disabledTowers(tt->coolId()));
391 if (!isDead && !isDisabled) return true;
392 return false;
393 }
394
395 StatusCode Run2TriggerTowerMaker::addOverlay(int bcid,float mu)
396 {
397 // Get the overlay data TTs from Bytestream
399 xAOD::TriggerTowerAuxContainer overlayDataTTsAux;
400 overlayDataTTs->setStore( &overlayDataTTsAux );
401 ATH_CHECK( m_bstowertool->loadTriggerTowers(*overlayDataTTs) ); // use L1Calo tool to fill xAOD::TriggerTowerContainer from BS
402
403 // put the overlay data TTs into a map
404 std::unordered_map<uint32_t,xAOD::TriggerTower*> overlayMap;
405 typedef std::unordered_map<uint32_t,xAOD::TriggerTower*>::iterator Itr;
406
407 // decorate the overlay TTs to indicate if they have been used or not
408 char decor_ttNotUsedInOverlay = 0;
409 char decor_ttUsedInOverlay = 1;
410 static const SG::Decorator<char> decor ("addedToSignal");
411 for (auto tt:*overlayDataTTs) {
412 // Let's exclude all dead and disabled towers
414 decor(*tt) = decor_ttNotUsedInOverlay;
415 overlayMap.insert( std::make_pair( tt->coolId() , tt ) );
416 }
417 }
418
419 // What is the size of the primary LUT readout?
420 bool findSizeOfPrimaryLUT(true);
421 unsigned int sizeOfPrimaryLUT(0);
422 uint8_t peakOfPrimary(0);
423
424 // Loop over primary TTs, match overlay TTs, and add LUT values
425 for (auto tt:*m_xaodTowers) {
426
427 // find size of primary LUT readout for first TT
428 if (findSizeOfPrimaryLUT) {
429 findSizeOfPrimaryLUT = false;
430 sizeOfPrimaryLUT = tt->lut_cp().size();
431 peakOfPrimary = tt->peak();
432 }
433
434 // Do we have a matching overlay tower?
435 Itr match = overlayMap.find( tt->coolId() );
436 if (match != overlayMap.end()) {
437
438 ATH_CHECK( addOverlay(bcid,mu,tt,(*match).second) );
439
440 // Let the overlay TT know that it has been used
441 decor(*match->second) = decor_ttUsedInOverlay;
442
443 } // end of match
444 } // end of loop over primary TTs
445
446 // Now we need to add all overlay TTs that have not been used so far
447 for (Itr i=overlayMap.begin();i!=overlayMap.end();++i) {
448 xAOD::TriggerTower* tt = (*i).second;
449 if (decor(*tt) == decor_ttNotUsedInOverlay) {
450 // Ensure that LUT vectors are the same size as the primary TTs
451 std::vector<uint8_t> overlay_lut_cp(sizeOfPrimaryLUT,0.);
452 std::vector<uint8_t> overlay_lut_jep(sizeOfPrimaryLUT,0.);
453
454 // Fill the LUT vectors
455 overlay_lut_cp.at(peakOfPrimary) = tt->cpET();
456 overlay_lut_jep.at(peakOfPrimary) = tt->jepET();
457
458 // Set the LUT vectors and peak
459 tt->setPeak( peakOfPrimary );
460 tt->setLut_cp( overlay_lut_cp );
461 tt->setLut_jep( overlay_lut_jep );
462
463 // add the overlay TT to the primary TT
464 m_xaodTowers->push_back( tt );
465 }
466 }
467
468 // Should be done!!!
469 return StatusCode::SUCCESS;
470 }
471
474 {
475 // Get the relevant databases
476 const L1CaloPprChanCalib* sigDB = m_chanCalibContainer->pprChanCalib(sigTT->coolId());
477 const L1CaloPprChanCalib* ovDB = m_chanCalibContaineroverlay->pprChanCalib(ovTT->coolId());
478
479 if (!sigDB) {
480 ATH_MSG_ERROR("Cannot find signal DB for tower 0x"<<std::hex<<sigTT->coolId()<<std::dec<<" Aborting...");
481 return StatusCode::FAILURE;
482 }
483
484 if (!ovDB) {
485 ATH_MSG_ERROR("Cannot find overlay DB for tower 0x"<<std::hex<<ovTT->coolId()<<std::dec<<" Aborting...");
486 return StatusCode::FAILURE;
487 }
488
489 // Let's begin with the same number of ADC samples
490 // retrieve signal and overlay digits
491 std::vector<int> sigDigits( std::begin(sigTT->adc()) , std::end(sigTT->adc()) );
492 std::vector<int> ovDigits( std::begin(ovTT->adc()) , std::end(ovTT->adc()) );
493 std::vector<int> normOverlayDigits;
494 normaliseDigits(sigDigits,ovDigits,normOverlayDigits);
495
496 // Get LUT input
497 std::vector<int> sigLutIn,ovLutIn;
498 ATH_CHECK( preProcessTower_getLutIn(bcid,mu,sigTT,sigDB,sigDigits,sigLutIn) );
499 ATH_CHECK( preProcessTower_getLutIn(bcid,mu,ovTT,ovDB,normOverlayDigits,ovLutIn) );
500
501 // LUT ouput
502 std::vector<int> lutOut_cp,lutOut_jep;
503 ATH_CHECK( calcLutOutCP(sigLutIn,sigDB,ovLutIn,ovDB,lutOut_cp) );
504 ATH_CHECK( calcLutOutJEP(sigLutIn,sigDB,ovLutIn,ovDB,lutOut_jep) );
505
506 // Not doing BCID yet.. can be added at a later date
507
508 std::size_t peak = lutOut_jep.size()/2; // both cp & jep have the same length
509 std::vector<uint_least8_t> etResultVectorCp { uint8_t(lutOut_cp[peak]) };
510 std::vector<uint_least8_t> etResultVectorJep { uint8_t(lutOut_jep[peak]) };
511
512 sigTT->setLut_cp(std::move(etResultVectorCp));
513 sigTT->setLut_jep(std::move(etResultVectorJep));
514
515 return StatusCode::SUCCESS;
516 }
517
518 StatusCode Run2TriggerTowerMaker::calcLutOutCP(const std::vector<int>& sigLutIn,const L1CaloPprChanCalib* sigDB,const std::vector<int>& ovLutIn,const L1CaloPprChanCalib* ovDB,std::vector<int>& output)
519 {
520 if (sigDB->lutCpStrategy() > 2 || ovDB->lutCpStrategy() > 2) {
521 ATH_MSG_ERROR("Cannot process calcLutOutCP as lutCpStrategy > 2");
522 return StatusCode::FAILURE;
523 }
524
525 double sigScale = (sigDB->lutCpStrategy() == 0) ? 1. : m_cpLutScale;
526 double sigSlope = sigScale * sigDB->lutCpSlope();
527 double sigOffset = sigScale * sigDB->lutCpOffset();
528
529 double ovScale = (ovDB->lutCpStrategy() == 0) ? 1. : m_cpLutScale;
530 double ovSlope = ovScale * ovDB->lutCpSlope();
531 double ovOffset = ovScale * ovDB->lutCpOffset();
532 double ovNoiseCut = ovScale * ovDB->lutCpNoiseCut();
533
534 calcCombinedLUT(sigLutIn,sigSlope,sigOffset,ovLutIn,ovSlope,ovOffset,ovNoiseCut,output);
535
536 return StatusCode::SUCCESS;
537 }
538
539 StatusCode Run2TriggerTowerMaker::calcLutOutJEP(const std::vector<int>& sigLutIn,const L1CaloPprChanCalib* sigDB,const std::vector<int>& ovLutIn,const L1CaloPprChanCalib* ovDB,std::vector<int>& output)
540 {
541 if (sigDB->lutJepStrategy() > 2 || ovDB->lutJepStrategy() > 2) {
542 ATH_MSG_ERROR("Cannot process calcLutOutJEP as lutJepStrategy > 2");
543 return StatusCode::FAILURE;
544 }
545
546 double sigScale = (sigDB->lutJepStrategy() == 0) ? 1. : m_jepLutScale;
547 double sigSlope = sigScale * sigDB->lutJepSlope();
548 double sigOffset = sigScale * sigDB->lutJepOffset();
549
550 double ovScale = (ovDB->lutCpStrategy() == 0) ? 1. : m_jepLutScale;
551 double ovSlope = ovScale * ovDB->lutJepSlope();
552 double ovOffset = ovScale * ovDB->lutJepOffset();
553 double ovNoiseCut = ovScale * ovDB->lutJepNoiseCut();
554
555 calcCombinedLUT(sigLutIn,sigSlope,sigOffset,ovLutIn,ovSlope,ovOffset,ovNoiseCut,output);
556
557 return StatusCode::SUCCESS;
558 }
559
560 void Run2TriggerTowerMaker::calcCombinedLUT(const std::vector<int>& sigIN,const int sigSlope,const int sigOffset,
561 const std::vector<int>& ovIN,const int ovSlope,const int ovOffset,const int ovNoiseCut,std::vector<int>& output)
562 {
563 // Modified version of TrigT1CaloTools/src/L1TriggerTowerTool
564
565 // (1) Calculate the Et conversion for the signal and the overlay
566 // (2) Combine the Et's
567 // (3) apply noise cut on combined Et sum
568 // (4) apply bitshift
569
570 output.clear();
571 output.reserve(sigIN.size()); // avoid frequent reallocations
572
573 for (unsigned int i=0;i<sigIN.size();++i) {
574 int out(0);
575 int signal = sigIN[i];
576 int overlay = ovIN[i];
577
578 int outSig = signal*sigSlope - sigOffset; // Et conversion for signal
579 int outOv = overlay*ovSlope - ovOffset; // Et conversion for overlay
580 int outTmp = outSig + outOv; // Combined Et
581
582 // Noise cut from overlay
583 if (outTmp >= ovNoiseCut) {
584 out = (outSig + outOv + 2048)>>12; // pedestal and bitshift
585 }
586
587 // keep things in range
588 if (out < 0) out = 0;
589 if (out > 255) out = 255;
590
591 output.push_back( out );
592 }
593 }
594
595 StatusCode Run2TriggerTowerMaker::preProcessTower_getLutIn(int bcid,float mu,xAOD::TriggerTower* tower,const L1CaloPprChanCalib* db,const std::vector<int>& digits,std::vector<int>& output)
596 {
597 // factorised version of Run2TriggerTowerMaker::preProcessTower
598
599 // process tower -- digital filter
600 std::vector<int> fir;
601 m_TTtool->fir(digits,
602 {db->firCoeff5(),db->firCoeff4(),db->firCoeff3(),db->firCoeff2(),db->firCoeff1()}, // reverse order in database
603 fir);
604
605 // pedestal correction
606 int pedCorrectionStrategy = db->lutCpStrategy();
607 std::vector<int16_t> correction;
608
609 // 1.) simulation and pedestal correction enabled
610 if (pedCorrectionStrategy == 1) {
611// cout<<"Using Simulation pedCorrectionStrategy"<<endl;
612 // case 1.) (database "abuses" pedFirSum to steer pedestal correction)
613 // apply the parameterized pedestal correction
614 int firPed = (db->firCoeff5() + db->firCoeff4() + db->firCoeff3() +
615 db->firCoeff2() + db->firCoeff1()) * int(db->pedMean() + 0.5);
616 m_TTtool->pedestalCorrection(fir,
617 firPed,
618 etaToElement(tower->eta(), tower->layer()),
619 tower->layer(),
620 bcid,
621 mu,
622 correction);
623 }
624
625 // 2.) data reprocessing and pedestal correction enabled
626 if (pedCorrectionStrategy == 2) {
627// cout<<"Using data pedCorrectionStrategy"<<endl;
628 // case 2.) (database "abuses" pedFirSum to steer pedestal correction)
629 // apply the recorded pedestal correction
630 if(!tower->correctionEnabled().empty() && tower->correctionEnabled().front()) {
631 std::size_t offset = (fir.size() - tower->correction().size())/2;
632
633 for(std::size_t i = offset, e = fir.size() - offset; i != e; ++i) {
634 correction.push_back(tower->correction()[i-offset]);
635 fir[i] -= tower->correction()[i-offset];
636 }
637 }
638 }
639
640 m_TTtool->dropBits(fir, db->firStartBit(), output);
641
642 return StatusCode::SUCCESS;
643 }
644
645 void Run2TriggerTowerMaker::normaliseDigits(const std::vector<int>& sigDigits,const std::vector<int>& ovDigits,std::vector<int>& normDigits)
646 {
647
648 // 3 possible cases:
649 // Case 1.) Signal MC and overlay data have same number of digits - easy peasy lemon squeezy
650 // Case 2.) Signal MC is larger - pad the overlay digits
651 // Case 3.) Signal MC is smaller - crop the overlay digits
652
653 // Case 1.)
654 if (sigDigits.size() == ovDigits.size()) {
655 for (auto x:ovDigits) normDigits.push_back( x );
656 }
657
658 // Case 2.)
659 if (sigDigits.size() > ovDigits.size()) {
660 unsigned int pad = (sigDigits.size() - ovDigits.size()) / 2;
661 for (unsigned int x=0;x<pad;++x) normDigits.push_back( 32 );
662 for (auto x:ovDigits) normDigits.push_back( x );
663 for (unsigned int x=0;x<pad;++x) normDigits.push_back( 32 );
664 }
665
666
667 // Case 3.)
668 if (sigDigits.size() < ovDigits.size()) {
669 unsigned int offset = (ovDigits.size() - sigDigits.size()) / 2;
670 for (unsigned int x=0;x<sigDigits.size();++x) {
671 unsigned int pos = x + offset;
672 normDigits.push_back( ovDigits[pos] );
673 }
674 }
675
676 }
677
678
681 StatusCode Run2TriggerTowerMaker::preProcess(int bcid,float mu)
682 {
683 // Loop over all existing towers and simulate preprocessor functions
684 for(auto tower : *m_xaodTowers) {
685 ATH_CHECK(preProcessTower(bcid,mu,tower));
686 }
687 return StatusCode::SUCCESS;
688 }
689
691 {
692
693 const L1CaloPprChanCalib* chanCalib = m_chanCalibContainer->pprChanCalib(tower->coolId());
694
695 if (!chanCalib) {
696 ATH_MSG_ERROR("Tower with coolId 0x"<<std::hex<<tower->coolId()<<std::dec<<" Not in database! Aborting ...");
697 return StatusCode::FAILURE;
698 }
699
700 // pedestal correction
701 int pedCorrectionStrategy(0);
702 // Regular job - no overlay
703 if (!m_doOverlay) {
704 if (chanCalib->pedFirSum() && !m_isDataReprocessing) pedCorrectionStrategy = 1; // simulation
705 if (chanCalib->pedFirSum() && m_isDataReprocessing) pedCorrectionStrategy = 2; // data reprocessing
706 }
707 if (m_doOverlay) {
708 pedCorrectionStrategy = chanCalib->lutCpStrategy();
709 }
710
712 std::vector<int> digits(std::begin(tower->adc()), std::end(tower->adc()));
713
715 std::vector<int> fir;
716 m_TTtool->fir(digits,
717 { chanCalib->firCoeff5(), chanCalib->firCoeff4(), chanCalib->firCoeff3(),
718 chanCalib->firCoeff2(), chanCalib->firCoeff1() }, // reverse order in database
719 fir);
720
722 std::vector<int16_t> correction;
723 // a few cases follow
724 // 1.) simulation and pedestal correction enabled
725 // 2.) data reprocessing and pedestal correction enabled
726 // 3.) pedestal correction disabled
727
728 // old method - now deprecated
729// if(chanCalib->pedFirSum() && !m_isDataReprocessing) {
730
731 // new method
732 if (pedCorrectionStrategy == 1) {
733 // case 1.) (database "abuses" pedFirSum to steer pedestal correction)
734 // apply the parameterized pedestal correction
735 int firPed = (chanCalib->firCoeff5() + chanCalib->firCoeff4() + chanCalib->firCoeff3() +
736 chanCalib->firCoeff2() + chanCalib->firCoeff1()) * int(chanCalib->pedMean() + 0.5);
737 m_TTtool->pedestalCorrection(fir,
738 firPed,
739 etaToElement(tower->eta(), tower->layer()),
740 tower->layer(),
741 bcid,
742 mu,
743 correction);
744 }
745
746 // old method - now deprecated
747 //else if(chanCalib->pedFirSum() && m_isDataReprocessing) {
748 if (pedCorrectionStrategy == 2) {
749
750 // case 2.) (database "abuses" pedFirSum to steer pedestal correction)
751 // apply the recorded pedestal correction
752 if(!tower->correctionEnabled().empty() && tower->correctionEnabled().front()) {
753 std::size_t offset = (fir.size() - tower->correction().size())/2;
754
755 for(std::size_t i = offset, e = fir.size() - offset; i != e; ++i) {
756 correction.push_back(tower->correction()[i-offset]);
757 fir[i] -= tower->correction()[i-offset];
758 }
759 ATH_MSG_VERBOSE("::correction: (from data");
760 printVec(this->msg(MSG::VERBOSE), correction);
761 } // in case the correction wasn't enabled in the readout nothing has to be done
762 }
763
764 // Case 3.) not yet implemented (will it ever be....??)
765
766 std::vector<int> lutIn;
767 m_TTtool->dropBits(fir, chanCalib->firStartBit(), lutIn);
768
769 // linear LUTs - CP
770 std::vector<int> lutOut_cp;
771 ATH_MSG_VERBOSE("::cp-lut: strategy: " << chanCalib->lutCpStrategy());
772 if(chanCalib->lutCpStrategy() < 3) {
773 // for new strategy lutSlope, lutOffset and lutNoiseCut are in units of LUTOut
774 // and need to be multiplied by the scale factor
775 double scale = (chanCalib->lutCpStrategy() == 0) ? 1. : m_cpLutScale;
776
777 m_TTtool->lut(lutIn,
778 scale * chanCalib->lutCpSlope(),
779 scale * chanCalib->lutCpOffset(),
780 scale * chanCalib->lutCpNoiseCut(),
781 32 /* unused */,
782 chanCalib->lutCpStrategy() > 0,
783 false, // TODO - disabled?
784 lutOut_cp);
785 } else if(chanCalib->lutCpStrategy() == 3) {
786 for(auto l : lutIn) lutOut_cp.push_back(non_linear_lut(l, chanCalib->lutCpOffset(), chanCalib->lutCpSlope(), chanCalib->lutCpNoiseCut(), chanCalib->lutCpScale(), chanCalib->lutCpPar1(), chanCalib->lutCpPar2(), chanCalib->lutCpPar3(), chanCalib->lutCpPar4()));
787 }
788 ATH_MSG_VERBOSE("::cp-lut: lut:");
789 printVec(this->msg(MSG::VERBOSE), lutOut_cp);
790
791
792 // linear LUTs - JEP
793 std::vector<int> lutOut_jep;
794 ATH_MSG_VERBOSE("::jep-lut: strategy: " << chanCalib->lutJepStrategy());
795 if(chanCalib->lutJepStrategy() < 3) {
796 // for new strategy lutSlope, lutOffset and lutNoiseCut are in units of LUTOut
797 // and need to be multiplied by the scale factor
798 double scale = (chanCalib->lutJepStrategy() == 0) ? 1. : m_jepLutScale;
799
800 m_TTtool->lut(lutIn,
801 scale * chanCalib->lutJepSlope(),
802 scale * chanCalib->lutJepOffset(),
803 scale * chanCalib->lutJepNoiseCut(),
804 32 /* unused */,
805 chanCalib->lutJepStrategy() > 0,
806 false, // TODO - disabled?
807 lutOut_jep);
808 } else if(chanCalib->lutJepStrategy() == 3) {
809 for(auto l : lutIn) lutOut_jep.push_back(non_linear_lut(l, chanCalib->lutJepOffset(), chanCalib->lutJepSlope(), chanCalib->lutJepNoiseCut(), chanCalib->lutJepScale(), chanCalib->lutJepPar1(), chanCalib->lutJepPar2(), chanCalib->lutJepPar3(), chanCalib->lutJepPar4()));
810 }
811 ATH_MSG_VERBOSE("::jep-lut: lut:");
812 printVec(this->msg(MSG::VERBOSE), lutOut_jep);
813
814
816 std::vector<int> BCIDOut;
817 if(!m_isDataReprocessing || tower->adc().size() >= 7) {
818 m_TTtool->bcid(fir, digits,
819 m_chanDefaults.peakFinderCond(),
820 chanCalib->satBcidThreshLow(),
821 chanCalib->satBcidThreshHigh(),
822 chanCalib->satBcidLevel(),
823 BCIDOut);
824 } else {
825 // in data reprocessing with less than 7 slices take decision from data
826 BCIDOut.assign(tower->bcidVec().begin(), tower->bcidVec().end());
827 ATH_MSG_VERBOSE("::bcidOut: (from data):");
828 printVec(this->msg(MSG::VERBOSE), BCIDOut);
829 }
830
831 std::size_t peak = lutOut_jep.size()/2; // both cp & jep have the same length
832 std::vector<uint_least8_t> etResultVectorCp { uint8_t(lutOut_cp[peak]) };
833 ATH_MSG_VERBOSE("::etResultVector: cp:");
834 printVec(this->msg(MSG::VERBOSE), etResultVectorCp);
835 std::vector<uint_least8_t> etResultVectorJep { uint8_t(lutOut_jep[peak]) };
836 ATH_MSG_VERBOSE("::etResultVector: jep:");
837 printVec(this->msg(MSG::VERBOSE), etResultVectorJep);
838
839 // identify BCID range
840 int range;
841 if(!(m_chanDefaults.decisionSource() & 0x1)) {
842 range = EtRange(digits[digits.size()/2], chanCalib->bcidEnergyRangeLow(), chanCalib->bcidEnergyRangeHigh());
843 } else {
844 range = EtRange(fir[fir.size()/2], chanCalib->bcidEnergyRangeLow(), chanCalib->bcidEnergyRangeHigh());
845 }
846 ATH_MSG_VERBOSE("::range: " << range);
847
848 // correct BCID for this range?
849 std::array<int, 3> bcidDecision {
850 {m_chanDefaults.bcidDecision1(), m_chanDefaults.bcidDecision2(), m_chanDefaults.bcidDecision3()}
851 };
852 ATH_MSG_VERBOSE("::bcidDecision:");
853 printVec(this->msg(MSG::VERBOSE), bcidDecision);
854
855 std::array<int, 3> satOverride {
856 {m_chanDefaults.satOverride1(), m_chanDefaults.satOverride2(), m_chanDefaults.satOverride3()}
857 };
858 ATH_MSG_VERBOSE("::satOverride:");
859 printVec(this->msg(MSG::VERBOSE), satOverride);
860
861 if((bcidDecision[range]) & (0x1 << (BCIDOut[BCIDOut.size()/2]))) {
862 if((satOverride[range]) & 0x1) {
863 // return saturation if set
864 etResultVectorCp[0] = SATURATIONVALUE;
865 etResultVectorJep[0] = SATURATIONVALUE;
866 }
867 } else {
868 // zero if fail BCID
869 etResultVectorCp[0] = 0;
870 etResultVectorJep[0] = 0;
871 }
872
873 // Overlay protection
874 if (m_inputTTLocation.key() == "NoneForOverlay") return StatusCode::SUCCESS;
875
876 tower->setLut_cp(std::move(etResultVectorCp));
877 tower->setLut_jep(std::move(etResultVectorJep));
878 tower->setBcidVec({uint8_t(BCIDOut[BCIDOut.size()/2])});
879 ATH_MSG_VERBOSE("::set bcidVec:");
880 printVec(this->msg(MSG::VERBOSE), tower->bcidVec());
881 tower->setPeak(0u); // we only added one item to etResultVector
882 if(m_decorateFIR) firDecorator(*tower) = fir[fir.size()/2];
883
886 tower->setBcidExt(std::vector<uint8_t>(tower->adc().size(), 0u));
887
888 // fill the pedestal correction
889 if(chanCalib->pedFirSum()) {
890 // online database abuses pedFirSum to steer pedestal correction
891 tower->setCorrectionEnabled(std::vector<uint8_t>(tower->lut_cp().size(), 1u));
892 tower->setCorrection(std::vector<int16_t>(tower->lut_cp().size(),
893 correction[correction.size()/2]));
894 ATH_MSG_VERBOSE("::set correction:");
895 printVec(this->msg(MSG::VERBOSE), tower->correction());
896 } else {
897 tower->setCorrectionEnabled(std::vector<uint8_t>(tower->lut_cp().size(), 0u));
898 tower->setCorrection(std::vector<int16_t>(tower->lut_cp().size(), 0u));
899 }
900 return StatusCode::SUCCESS;
901 }
902
909 {
910 ATH_MSG_DEBUG("Storing TTs in DataVector");
911 if(m_ZeroSuppress) {
912 // remove trigger towers whose energy is 0
914 [](const xAOD::TriggerTower* tt){
915 return tt->cpET() == 0 && tt->jepET() == 0;
916 }),
917 m_xaodTowers->end());
918 }
919
920
921
922 if (m_cellType == TRIGGERTOWERS) {
924 ATH_CHECK(output.record(std::move(m_xaodTowers), std::move(m_xaodTowersAux)));
925 }
926 else if (m_cellType == TTL1) {
928 ATH_CHECK(output.record(std::move(m_xaodTowers), std::move(m_xaodTowersAux)));
929 }
930
931 return StatusCode::SUCCESS;
932 } // end of LVL1::Run2TriggerTowerMaker::store(){
933
934
938 {
939 ATH_MSG_INFO("Retrieve input TriggerTowers " << m_inputTTLocation.key());
941 ATH_CHECK(inputTTs.isValid());
942 ATH_MSG_INFO("Found " << inputTTs->size() << " input TriggerTowers");
943
944 for(const xAOD::TriggerTower* tower : *inputTTs) {
945 xAOD::TriggerTower* t = (*m_xaodTowers)[m_curIndex++] = new xAOD::TriggerTower;
946 *t = *tower;
947 }
948
950 // /// So clean-up m_xaodTowers before these cause problems later.
952 [](const xAOD::TriggerTower* tt){return (tt == 0);}),
953 m_xaodTowers->end());
954
955 // Remove dead and disabled towers
957 [this](const xAOD::TriggerTower* tt){return !IsGoodTower(tt,m_deadChannelsContainer,m_disabledTowersContainer);}),
958 m_xaodTowers->end());
959
960 return StatusCode::SUCCESS;
961 } // end of getTriggerTowers()
962
965 {
966 // Find LAr towers in TES
967 StatusCode sc1 = StatusCode::SUCCESS;
969 if(!EMTowers.isValid()){
970 ATH_MSG_WARNING("EM LArTTL1Container not found");
971 sc1 = StatusCode::FAILURE;
972 }
973
974 StatusCode sc2 = StatusCode::SUCCESS;
976 if(!HECTowers.isValid()){
977 ATH_MSG_WARNING("Had LArTTL1Container not found");
978 sc2 = StatusCode::FAILURE;
979 }
980
981 // Find Tile towers in TES
982 StatusCode sc3 = StatusCode::SUCCESS;
984 if(!TileTowers.isValid()){
985 ATH_MSG_WARNING("Tile LArTTL1Container not found");
986 sc3 = StatusCode::FAILURE;
987 }
988
989 if(m_requireAllCalos && ((sc1==StatusCode::FAILURE) ||
990 (sc2==StatusCode::FAILURE) ||
991 (sc3==StatusCode::FAILURE))) {
992 ATH_MSG_ERROR("Can't find calo towers - stopping processing" << endmsg
993 << "Found Em LArTTL1 : "<<sc1 << endmsg
994 << "Found Had LArTTL1 : "<<sc2 << endmsg
995 << "Found TileTTL1 : "<<sc3<< endmsg
996 );
997 return StatusCode::FAILURE;
998 }
999
1000 // lets now try to create some trigger towers
1001 if(sc1 == StatusCode::SUCCESS) {
1002 processLArTowers(EMTowers.cptr());
1003 }
1004 if(sc2 == StatusCode::SUCCESS) {
1005 processLArTowers(HECTowers.cptr());
1006 }
1007 if(sc3 == StatusCode::SUCCESS) {
1008 processTileTowers(TileTowers.cptr());
1009 }
1010
1012 // /// So clean-up m_xaodTowers before these cause problems later.
1013 m_xaodTowers->erase(std::remove_if(m_xaodTowers->begin(), m_xaodTowers->end(),
1014 [](const xAOD::TriggerTower* tt){return (tt == 0);}),
1015 m_xaodTowers->end());
1016
1017 // Remove dead and disabled towers
1018 m_xaodTowers->erase(std::remove_if(m_xaodTowers->begin(), m_xaodTowers->end(),
1019 [this](const xAOD::TriggerTower* tt){return !IsGoodTower(tt,m_deadChannelsContainer,m_disabledTowersContainer);}),
1020 m_xaodTowers->end());
1021
1022 return StatusCode::SUCCESS;
1023 }
1024
1027 {
1028 int towerNumber=0;
1029 for(const LArTTL1* tower : *towers){
1030 ATH_MSG_VERBOSE("Looking at retrieved tower number "<<towerNumber++<<" ***********");
1031
1032 // Obtain identifier
1033 Identifier id = tower->ttOfflineID();
1034 double eta = IDeta(id, m_caloId);
1035 double phi = IDphi(id, m_caloId);
1036 int layer = int(m_caloId->sampling(id) != 0);
1037 L1CaloCoolChannelId coolId = channelId(eta, phi, layer);
1038
1039 // Tower amplitudes and type
1040 int nsamples = tower->nsamples();
1041 std::vector<float> tower_amps = tower->samples();
1042
1043 // Now calibrate tower_amps then fill TriggerTower amplitude vector
1044 // TTL1 should have 7 samples, but this little kludge handles other
1045 // eventualities, provided peak is in centre of the pulse
1046 int offset = (nsamples - (s_FIRLENGTH+2))/2;
1047 std::vector<double> amps(s_FIRLENGTH+2);
1048
1049 ATH_MSG_VERBOSE("nsamples = " << nsamples << " offset = " << offset);
1050
1051 for(int i = 0; i < s_FIRLENGTH+2; i++) {
1052 int j = i + offset;
1053 if(j >= 0 && j < nsamples) {
1054 amps[i] = tower_amps[j];
1055 }
1056 else {
1057 amps[i] = 0.;
1058 }
1059 ATH_MSG_VERBOSE("amps[" << i << "] = " << amps[i]);
1060 }
1061
1062 // Create TriggerTower
1063 xAOD::TriggerTower* t = (*m_xaodTowers)[m_curIndex++] = new xAOD::TriggerTower;
1064 t->setCoolId(coolId.id());
1065 t->setEta(eta);
1066 t->setPhi(phi);
1067 m_xaodTowersAmps[t->index()] = std::move(amps);
1068 } // end for loop
1069 }
1070
1072 {
1073 // Step over all towers
1074 int towerNumber=0;
1075 for(const TileTTL1* tower : *towers) {
1076 ATH_MSG_VERBOSE("Looking at retrieved tower number "<<towerNumber++<<" ***********");
1077
1078 // Obtain identifier
1079 Identifier id = tower->TTL1_ID();
1080 double cal = m_TileToMeV;//calib(id, m_caloId)*m_TileToMeV;
1081
1082 // Check this tower is used by the trigger
1083 // don't use gap or mbias scinitllators
1084 if(m_caloId->is_tile(id)) {
1085 double tower_eta = IDeta(id, m_caloId);
1086 double tower_phi = IDphi(id, m_caloId);
1087
1088 // need to convert tower energy to E_t later
1089 unsigned Ieta = unsigned(fabs(tower_eta)*10.0);
1090 if(Ieta >= m_maxIetaBins){
1091 ATH_MSG_WARNING("TileTTL1 with invalid index for m_sinThetaHash: Ieta = " << Ieta);
1092 Ieta = 0u;
1093 }
1094
1095 /* Extract amplitudes and rescale according to tower eta */
1096 int nsamples = tower->nsamples();
1097 std::vector<float> tower_amps = tower->fsamples();
1098
1099 /* Debug message */
1100 ATH_MSG_VERBOSE(" nsamples = " << nsamples);
1101
1102 // Want 7 samples, but this little kludge allows us to accept other
1103 // numbers, provided peak is in centre of the pulse
1104 int offset = (nsamples - (s_FIRLENGTH+2))/2;
1105 std::vector<double> amps(s_FIRLENGTH+2);
1106 for(int i = 0; i < 7; i++) {
1107 int j = i + offset;
1108 if(j >= 0 && j < nsamples) {
1109 amps[i] = (tower_amps[j]-m_TileTTL1Ped)*m_sinThetaHash[Ieta]*cal; // rescale to MeV
1110 }
1111 else {
1112 amps[i] = 0.;
1113 }
1114 /* Debug message */
1115 ATH_MSG_VERBOSE("amps[" << i << "] = " << amps[i]);
1116 }
1117
1118 // Create TriggerTower
1119 // m_xaodTowers->push_back(new xAOD::TriggerTower);
1120 // auto t = m_xaodTowers->back();
1121 xAOD::TriggerTower* t = (*m_xaodTowers)[m_curIndex++] = new xAOD::TriggerTower;
1122 t->setCoolId(channelId(tower_eta, tower_phi, 1).id());
1123 t->setEta(tower_eta);
1124 t->setPhi(tower_phi);
1125 m_xaodTowersAmps[t->index()] = std::move(amps);
1126 } // end check on whether tower is used
1127 } // end for loop
1128
1129 return;
1130 }
1131
1133 void Run2TriggerTowerMaker::digitize(const EventContext& ctx)
1134 {
1135 CLHEP::HepRandomEngine* rndmADCs = m_rndmADCs->getEngine (ctx);
1136
1137 // Loop over all existing towers and digitize pulses
1138 for(auto tower : *m_xaodTowers) {
1139 // First process EM layer
1140 L1CaloCoolChannelId id(tower->coolId());
1141 std::vector<int> digits = ADC(rndmADCs, id, m_xaodTowersAmps[tower->index()]); // ADC simulation
1142 tower->setAdc(std::vector<uint16_t>(std::begin(digits), std::end(digits)));
1143 tower->setAdcPeak(digits.size()/2);
1144 }
1145 }
1146
1147 std::vector<int> Run2TriggerTowerMaker::ADC(CLHEP::HepRandomEngine* rndmADCs,
1148 L1CaloCoolChannelId channel, const std::vector<double>& amps) const
1149 {
1150 auto* chanCalib = m_chanCalibContainer->pprChanCalib(channel);
1151 if(!chanCalib) { ATH_MSG_WARNING("No database entry for tower " << channel.id()); return {}; }
1152 double ped = chanCalib->pedMean();
1153
1154 // dice the calibration uncertainty if requested
1155 double adcCal = (m_gainCorr > 0.) ? CLHEP::RandGaussZiggurat::shoot(rndmADCs, 1., m_gainCorr) : 1.;
1156
1157 std::vector<int> digits;
1158 const int nSamples = amps.size();
1159 digits.reserve(nSamples);
1160 for(int i = 0; i < nSamples; ++i) {
1161 // dice the adc noise if requested
1162 double adcNoise = (m_adcVar > 0.) ? CLHEP::RandGaussZiggurat::shoot(rndmADCs,0.,m_adcVar) : 0.;
1163
1164 int digit = int((amps[i]*adcCal/m_adcStep) + ped + adcNoise);
1165 if(digit > ADCMAX) digit = ADCMAX;
1166 if(digit < 0) digit = 0;
1167 digits.push_back(digit);
1168 }
1169 return digits;
1170 }
1171
1172 int Run2TriggerTowerMaker::EtRange(int et, unsigned short bcidEnergyRangeLow, unsigned short bcidEnergyRangeHigh) const
1173 {
1174 if(et < bcidEnergyRangeLow) return 0;
1175 if(et < bcidEnergyRangeHigh) return 1;
1176 return 2;
1177 }
1178
1180 {
1181 int region = l1id->region(id);
1182 int ieta = l1id->eta(id);
1183 int sign = l1id->pos_neg_z(id);
1184
1185 double gran[4] = {0.1, 0.2, 0.1, 0.425};
1186 double offset[4] = {0., 2.5, 3.1, 3.2};
1187 double eta;
1188
1189 if(region>=0 && region<=3) {
1190 eta = sign* (((ieta+0.5) * gran[region]) + offset[region]);
1191 }
1192 else {
1193 eta = 0.;
1194 }
1195
1196 return eta;
1197 }
1198
1199
1201 {
1202 Identifier regId = l1id->region_id(id);
1203
1204 double phiMax = l1id->phi_max(regId);
1205 int iphi = l1id->phi(id);
1206 double phi = (iphi+0.5)*2*M_PI/(phiMax+1);
1207
1208 return phi;
1209 }
1210
1216 {
1217 int crate, module, channel;
1218 m_mappingTool->mapping(eta, phi, layer, crate, module, channel);
1219 int slot = module + 5;
1220 int pin = channel % 16;
1221 int asic = channel / 16;
1222 return L1CaloCoolChannelId(crate, L1CaloModuleType::Ppm, slot, pin, asic, false);
1223 }
1224
1225 int Run2TriggerTowerMaker::etaToElement(float feta, int layer) const
1226 {
1227 constexpr static int NELEMENTS = 33;
1229 float shiftedEta = feta + 4.9;
1230 uint eta = (uint)floor(shiftedEta*10.0);
1231 if(fabs(shiftedEta*10.0 - (uint)(eta+1)) < 0.01) eta++;
1232 if(fabs(shiftedEta) < 0.01) eta = 0;
1233
1234 constexpr int nBins = 16;
1235 constexpr uint map[nBins] = {2,6,10,14,17,19,21,23,75,77,79,80,83,87,91,95};
1236 int element = -1;
1237 if(eta > 23 && eta < 74) {
1238 element = eta - 16;
1239 } else {
1240 for(int i = 0; i < nBins; i++) {
1241 if(eta == map[i]) {
1242 if(i < 8) element = i;
1243 else element = i + 50;
1244 break;
1245 }
1246 }
1247 }
1248 if (layer == 1 && (element == 0 || element == 64)) element = 1; // FCal2-2
1249 else if (layer == 1 && (element == 1 || element == 65)) element = 0; // FCal3-2
1250 else if (layer == 1 && (element == 2 || element == 62)) element = 3; // FCal2-1
1251 else if (layer == 1 && (element == 3 || element == 63)) element = 2; // FCal3-1
1252 else if (element > 32) element = 65-element;
1253
1254 // element 29 = FCal2-1, element 30 = FCal3-1, element 31 = FCal2-2, element 32 = FCal3-2
1255 element = NELEMENTS-element-1;
1256
1257 return element;
1258 }
1259
1260 // This is the non-linear LUT function corresponding to strategy 3.
1261 // This should actually go into LVL1::L1TriggerTowerTools (TrigT1CaloTools)
1262 // but for now we keep it here to keep the number of touched packages small
1263 // and make it easier to change some parts of the definition later on.
1264 int Run2TriggerTowerMaker::non_linear_lut(int lutin, unsigned short offset, unsigned short slope, unsigned short noiseCut, unsigned short scale, short par1, short par2, short par3, short par4) {
1265 // turn shorts into double (database fields are shorts ... )
1266
1267 // turn shorts into double
1268 double nll_slope = 0.001 * scale;
1269 double nll_offset = 0.001 * par1;
1270 double nll_ampl = 0.001 * par2;
1271 double nll_expo = 0.;
1272 if(par3) {
1273 nll_expo = -1. / (4096 * 0.001*par3);
1274 } else {
1275 nll_ampl = 0.;
1276 }
1277 double nll_noise = 0.001 * par4;
1278
1279 // noise cut
1280 if (lutin * slope < offset + nll_noise * noiseCut) {
1281 return 0;
1282 }
1283
1284 // actual calculation
1285 int output = int((((int)(2048 + nll_slope * (lutin * slope - offset)))>>12) + nll_offset + nll_ampl * std::exp(nll_expo * (lutin * slope - offset)));
1286 if(output >= 255) return 255;
1287 if(output < 0) return 0;
1288 return output;
1289 }
1290
1291} // end of namespace bracket
#define M_PI
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#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)
#define CHECK(...)
Evaluate an expression and check for errors.
Helper class to provide type-safe access to aux data.
unsigned int uint
Handle class for reading a decoration on an object.
Handle class for reading from StoreGate.
int sign(int a)
TileContainer< TileTTL1 > TileTTL1Container
#define x
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > renounce(T &h)
ServiceHandle< StoreGateSvc > & evtStore()
const ServiceHandle< StoreGateSvc > & detStore() const
Helper class for offline TT identifiers.
Definition CaloLVL1_ID.h:66
int phi_max(const Identifier regId) const
min value of phi index (-999 == failure)
Identifier region_id(int pos_neg_z, int sampling, int region) const
build a region (of towers) identifier
int region(const Identifier id) const
return region according to :
int pos_neg_z(const Identifier id) const
return pos_neg_z according to :
int eta(const Identifier id) const
return eta according to :
int phi(const Identifier id) const
return phi according to :
Encapsulates the ID of one channel of conditions data in COOL, ie the ID of a row in a table.
unsigned int id() const
Folder <-> Object mapping for /TRIGGER/L1Calo/V1/Conditions/DisabledTowers .
const L1CaloPpmDeadChannels * ppmDeadChannels(unsigned int channelId) const
Folder <-> Object mapping for /TRIGGER/L1Calo/V1/Calibration/PpmDeadChannels .
Folder <-> Object mapping for /TRIGGER/L1Calo/V2/Calibration/Physics/PprChanCalib .
unsigned short lutJepStrategy() const
unsigned short lutCpSlope() const
unsigned short satBcidLevel() const
unsigned short lutCpScale() const
unsigned short lutJepNoiseCut() const
unsigned short lutJepSlope() const
unsigned short lutCpStrategy() const
unsigned int pedFirSum() const
unsigned short satBcidThreshLow() const
unsigned short firStartBit() const
unsigned short lutCpOffset() const
unsigned short lutJepScale() const
unsigned short bcidEnergyRangeLow() const
unsigned short satBcidThreshHigh() const
unsigned short lutCpNoiseCut() const
unsigned short bcidEnergyRangeHigh() const
unsigned short lutJepOffset() const
Container class for LArTTL1.
Liquid Argon TT L1 sum class.
Definition LArTTL1.h:29
void processLArTowers(const LArTTL1Container *)
extract amplitudes from TTL1
SG::ReadCondHandleKey< L1CaloPpmDeadChannelsContainer > m_deadChannelsKey
int EtRange(int et, unsigned short bcidEnergyRangeLow, unsigned short bcidEnergyRangeHigh) const
SG::ReadHandleKey< xAOD::TriggerTowerContainer > m_inputTTLocation
L1CaloDisabledTowersContainer * m_disabledTowersContaineroverlay
std::vector< std::vector< double > > m_xaodTowersAmps
SG::ReadHandleKey< TileTTL1Container > m_TileTTL1ContainerName
SG::ReadCondHandleKey< L1CaloPprChanCalibContainer > m_chanCalibKey
L1CaloPpmDeadChannelsContainer * m_deadChannelsContaineroverlay
bool IsGoodTower(const xAOD::TriggerTower *tt, const L1CaloPpmDeadChannelsContainer *dead, const L1CaloDisabledTowersContainer *disabled) const
StatusCode execute(const EventContext &ctx)
Checks that the Cell Type is supported (terminates with errors if not) and calls relevant routine to ...
bool IsDeadChannel(const L1CaloPpmDeadChannels *db) const
Database helper functions for dead and disabled towers.
std::unique_ptr< xAOD::TriggerTowerContainer > m_xaodTowers
SG::WriteHandleKey< xAOD::TriggerTowerContainer > m_outputLocationRerun
ToolHandle< IL1TriggerTowerTool > m_TTtool
void calcCombinedLUT(const std::vector< int > &sigIN, const int sigSlope, const int sigOffset, const std::vector< int > &ovIN, const int ovSlope, const int ovOffset, const int ovNoiseCut, std::vector< int > &output)
int non_linear_lut(int lutin, unsigned short offset, unsigned short slope, unsigned short noiseCut, unsigned short scale, short par1, short par2, short par3, short par4)
bool IsDisabledChannel(const L1CaloDisabledTowers *db) const
double IDphi(const Identifier &id, const CaloLVL1_ID *caloId)
L1CaloPprChanDefaults m_chanDefaults
ToolHandle< IL1CaloMappingTool > m_mappingTool
ServiceHandle< IAthRNGSvc > m_rngSvc
void normaliseDigits(const std::vector< int > &sigDigits, const std::vector< int > &ovDigits, std::vector< int > &normDigits)
normalise the number of ADC digits for overlay
L1CaloPprChanCalibContainer * m_chanCalibContaineroverlay
StatusCode preProcessTower(int bcid, float mu, xAOD::TriggerTower *tower)
int etaToElement(float feta, int layer) const
SG::ReadHandleKey< TrigConf::L1Menu > m_L1MenuKey
SG::ReadHandleKey< xAOD::EventInfo > m_xaodevtKey
virtual StatusCode addOverlay(int bcid, float mu)
Add overlay data.
const L1CaloPpmDeadChannelsContainer * m_deadChannelsContainer
StatusCode getTriggerTowers()
gets collection of input TriggerTowers for reprocessing
StatusCode getCaloTowers()
fetch Calorimeter Towers
double IDeta(const Identifier &id, const CaloLVL1_ID *caloId)
functions to extract eta, phi coordinates from calo tower identifiers
L1CaloCoolChannelId channelId(double eta, double phi, int layer)
Compute L1CaloCoolChannelId (including support for old geometries).
StatusCode calcLutOutCP(const std::vector< int > &sigLutIn, const L1CaloPprChanCalib *sigDB, const std::vector< int > &ovLutIn, const L1CaloPprChanCalib *ovDB, std::vector< int > &output)
calculate LUT out
Run2TriggerTowerMaker(const std::string &name, ISvcLocator *pSvcLocator)
SG::ReadHandleKey< LArTTL1Container > m_EmTTL1ContainerName
ToolHandle< LVL1BS::ITrigT1CaloDataAccessV2 > m_bstowertool
static constexpr unsigned int m_maxIetaBins
const L1CaloPprChanCalibContainer * m_chanCalibContainer
StatusCode preProcessTower_getLutIn(int bcid, float mu, xAOD::TriggerTower *tower, const L1CaloPprChanCalib *db, const std::vector< int > &digits, std::vector< int > &output)
PreProcess up to LUT in.
void digitize(const EventContext &ctx)
Convert analogue pulses to digits.
StatusCode calcLutOutJEP(const std::vector< int > &sigLutIn, const L1CaloPprChanCalib *sigDB, const std::vector< int > &ovLutIn, const L1CaloPprChanCalib *ovDB, std::vector< int > &output)
SG::ReadDecorHandleKey< xAOD::EventInfo > m_actMuKey
SG::ReadHandleKey< LArTTL1Container > m_HadTTL1ContainerName
SG::ReadCondHandleKey< L1CaloDisabledTowersContainer > m_disabledTowersKey
std::unique_ptr< xAOD::TriggerTowerAuxContainer > m_xaodTowersAux
StatusCode preProcess(int bcid, float mu)
Simulate PreProcessing on analogue amplitudes.
std::array< double, m_maxIetaBins > m_sinThetaHash
instead of calculating the expression: double theta =2.
void processTileTowers(const TileTTL1Container *)
StatusCode store()
Stores Trigger Towers in the TES, at a location defined in m_outputLocation.
std::vector< int > ADC(CLHEP::HepRandomEngine *rndmADCs, L1CaloCoolChannelId channel, const std::vector< double > &amps) const
Functions to simulate processing of tower signals.
const L1CaloDisabledTowersContainer * m_disabledTowersContainer
SG::ReadCondHandleKey< L1CaloPprChanDefaultsContainer > m_chanDefaultsKey
SG::WriteHandleKey< xAOD::TriggerTowerContainer > m_outputLocation
void handle(const Incident &)
Best if initialisation which uses COOL-derived values is done here rather than in initialize().
static const std::string xAODTriggerTowerLocation
static const std::string xAODTriggerTowerRerunLocation
Handle class for reading a decoration on an object.
bool isPresent() const
Is the referenced container present in SG?
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
double TTL1Calib(const Identifier &) const
Returns the factor which converts amplitude in pCb to mV in TTL1.
Definition TileInfo.h:112
double TTL1Ped(const Identifier &) const
Returns the pedestal (in mV) for TTL1 adcs.
Definition TileInfo.h:139
STL class.
uint32_t eventTypeBitmask() const
The event type bitmask.
@ IS_SIMULATION
true: simulation, false: data
void setPeak(uint8_t)
set peak
void setBcidVec(const std::vector< uint8_t > &)
set bcidVec
uint32_t coolId() const
Tower identifiers.
void setCorrectionEnabled(const std::vector< uint8_t > &)
set correctionEnabled
void setCorrection(const std::vector< int16_t > &)
set correction
const std::vector< uint8_t > & correctionEnabled() const
get correctionEnabled
void setLut_cp(const std::vector< uint8_t > &)
set lut_cp
virtual double eta() const final
The pseudorapidity ( ) of the particle.
void setBcidExt(const std::vector< uint8_t > &)
set bcidExt
void setLut_jep(const std::vector< uint8_t > &)
set lut_jep
const std::vector< uint16_t > & adc() const
get adc
int layer() const
get layer ( 0 = EM, 1 = Had, 2 = FCAL23) - to be confirmed
const std::vector< int16_t > & correction() const
get correction
const std::vector< uint8_t > & lut_cp() const
get lut_cp
const std::vector< uint8_t > & bcidVec() const
get bcidVec
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:359
bool overlay
Definition listroot.cxx:42
eFexTowerBuilder creates xAOD::eFexTowerContainer from supercells (LATOME) and triggerTowers (TREX) i...
Definition MsgLevel.h:28
SG::Decorator< T, ALLOC > Decorator
Helper class to provide type-safe access to aux data, specialized for JaggedVecElt.
Definition AuxElement.h:576
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.
EventInfo_v1 EventInfo
Definition of the latest event info version.
TriggerTowerContainer_v2 TriggerTowerContainer
Define the latest version of the TriggerTower container.
TriggerTower_v2 TriggerTower
Define the latest version of the TriggerTower class.
TriggerTowerAuxContainer_v2 TriggerTowerAuxContainer
Define the latest version of the TriggerTower auxiliary container.
Extra patterns decribing particle interation process.
MsgStream & msg
Definition testRead.cxx:32