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