ATLAS Offline Software
Loading...
Searching...
No Matches
L1CaloRampMaker.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <fstream>
8#include <utility> // make_pair
9
11
15
18#include "CaloEvent/CaloCell.h"
19
23
27
28
29// temporary includes to work around limitations in L1CaloxAODOfflineTriggerTowerTools
34
35
36// define Accessors
37namespace {
38 const xAOD::TriggerTower::ConstAccessor<float> ttCellsEnergy("CaloCellEnergy");
39 const xAOD::TriggerTower::ConstAccessor<float> ttCellsET("CaloCellET");
40}
41
42L1CaloRampMaker::L1CaloRampMaker(const std::string& name, ISvcLocator* pSvcLocator)
43 : AthAlgorithm(name, pSvcLocator),
44 m_triggerTowerContainerName(LVL1::TrigT1CaloDefs::xAODTriggerTowerLocation),
45 m_outputFolderName("/L1CaloRampMaker/L1CaloRampDataContainer"),
46 m_gainStrategyFolder("/TRIGGER/Receivers/Conditions/Strategy"),
47 m_doLAr(false),
48 m_doTile(false),
49 m_isGain1(true),
50 m_isOvEmb(false),
51 m_isOvEmec(false),
52 m_isFcalLowEta(false),
53 m_isFcalHighEta(false),
54 m_checkProvenance(false),
56 m_nSteps(9),
59 m_ttTool("LVL1::L1TriggerTowerToolRun3/L1TriggerTowerToolRun3"),
60 m_xAODTTTools("LVL1::L1CaloxAODOfflineTriggerTowerTools/L1CaloxAODOfflineTriggerTowerTools", this),
61 m_jmTools("LVL1::L1CaloOfflineTriggerTowerTools/L1CaloOfflineTriggerTowerTools", this),
62 m_nEvent(1),
63 m_firstEvent(true),
64 m_nTTs(0),
65 m_lvl1Helper(nullptr),
66 m_rampDataContainer(nullptr)
67
68{
69 declareProperty("TriggerTowerCollectionName", m_triggerTowerContainerName);
70 declareProperty("OutputFolderName", m_outputFolderName);
71 declareProperty("GainStrategyFolder", m_gainStrategyFolder);
72 declareProperty("DoLAr", m_doLAr);
73 declareProperty("DoTile", m_doTile);
74 declareProperty("IsGain1", m_isGain1);
75 declareProperty("IsOvEmb", m_isOvEmb);
76 declareProperty("IsOvEmec", m_isOvEmec);
77 declareProperty("IsFcalLowEta", m_isFcalLowEta);
78 declareProperty("IsFcalHighEta", m_isFcalHighEta);
79 declareProperty("CheckProvenance", m_checkProvenance);
80 declareProperty("EventsPerEnergyStep", m_nEventsPerStep);
81 declareProperty("NumberOfEnergySteps", m_nSteps);
82 declareProperty("FADCSaturationCut", m_fadcSaturationCut);
83 declareProperty("TileSaturationCut", m_tileSaturationCut);
84 declareProperty("L1TriggerTowerToolRun3", m_ttTool);
85 declareProperty("SpecialChannelRange", m_specialChannelRange);
86}
87
91
93{
94
95 CHECK(m_caloCellsKey.initialize());
96
97 const CaloIdManager *caloMgr = nullptr;
98 CHECK(detStore()->retrieve(caloMgr));
99 m_lvl1Helper = caloMgr->getLVL1_ID();
100 if(!m_lvl1Helper) {
101 ATH_MSG_FATAL( "Cannot access CaloLVL1_ID helper." );
102 return StatusCode::FAILURE;
103 }
104
105 ATH_CHECK( m_cablingKey.initialize() );
106 ATH_CHECK(m_ttTool.retrieve());
107 ATH_CHECK(m_xAODTTTools.retrieve());
108 ATH_CHECK(m_jmTools.retrieve());
109
110 ATH_CHECK( m_strategy.initialize() );
112 ATH_CHECK( m_pprChanCalibContainer.initialize() );
113
114 return StatusCode::SUCCESS;
115}
116
118{
119 // Skip spurious events
120 unsigned int wantedEvents = m_nEventsPerStep*m_nSteps;
121 if (m_nEvent > wantedEvents) {
122 if (m_nEvent == wantedEvents+1) {
123 ATH_MSG_INFO( "Processed " << wantedEvents
124 << " events, skipping the rest" );
125 }
126 ++m_nEvent;
127 return StatusCode::SUCCESS;
128 }
129
130 const xAOD::EventInfo* eventInfo = nullptr;
131 CHECK(evtStore()->retrieve(eventInfo));
132 if (eventInfo->eventNumber() == 0 && m_nEvent > 1) {
133 // Only allow event 0 as first event
134 ATH_MSG_WARNING( "Skipping spurious event number 0" );
135 return StatusCode::SUCCESS;
136 }
137
138 const xAOD::TriggerTowerContainer *tts = nullptr;
139 auto sc = evtStore()->retrieve(tts, m_triggerTowerContainerName);
140 if(!sc.isSuccess()) {
141 ATH_MSG_ERROR( "Cannot retrieve TriggerTowerCollection '"
142 << m_triggerTowerContainerName << "' from StoreGate." );
143 return StatusCode::RECOVERABLE;
144 }
145
146
147 const EventContext& ctx = getContext();
148
150
151 const unsigned evt=ctx.eventID().event_number();
152 ATH_MSG_DEBUG("Event " << evt << " contains " << cells->size() << " CaloCells" );
153 const CaloCellContainer* cellCont = cells.get();
154
155
156
157 m_jmTools->caloCells(cellCont);
158
159 // init trigger tower to cell mapping
160 CHECK(m_xAODTTTools->initCaloCells());
161 ATH_MSG_DEBUG("GAIN STRATEGY " << m_strategy);
162
163
164
165 if(m_firstEvent) {
166 m_nTTs = tts->size();
167 unsigned int runNumber = eventInfo->runNumber();
168 std::string gainStrategy("");
169 const CondAttrListCollection* gainStrategyColl = 0;
170 sc = detStore()->retrieve(gainStrategyColl, m_gainStrategyFolder);
171 if(sc.isSuccess()) {
172 CondAttrListCollection::const_iterator itr = gainStrategyColl->begin();
173 CondAttrListCollection::const_iterator itrE = gainStrategyColl->end();
174 bool consistent(true);
175 for (; itr != itrE; ++itr) {
176 const unsigned int channel = itr->first;
177 if (channel != 1 && channel != 2) continue;
178 const coral::AttributeList& attrList = itr->second;
179 const std::string strategy(attrList["name"].data<std::string>());
180 const std::string status(attrList["status"].data<std::string>());
181 ATH_MSG_INFO( "Gain Strategy: channel = " << channel
182 << ", name = " << strategy
183 << ", status = " << status );
184 if (gainStrategy.empty()) gainStrategy = std::move(strategy);
185 else if (gainStrategy != strategy) consistent = false;
186 }
187 std::string newStrategy("");
188 if (runNumber == 219978) newStrategy = "GainOneOvEmecFcalLowEta";
189 if (runNumber == 219979) newStrategy = "GainOneOvEmbFcalHighEta";
190 if (runNumber == 219980) newStrategy = "CalibGainsEt";
191 if (runNumber == 220013) newStrategy = "GainOneOvEmecFcalLowEta";
192 if (runNumber == 220014) newStrategy = "GainOneOvEmbFcalHighEta";
193 if (runNumber == 220015) newStrategy = "CalibGainsEt";
194 if (runNumber == 222871) newStrategy = "GainOne";
195 if (runNumber == 222872) newStrategy = "GainOne";
196 if (runNumber == 222873) newStrategy = "GainOne";
197 if (runNumber == 223073) newStrategy = "GainOne";
198 if (runNumber == 223074) newStrategy = "GainOne";
199 if (runNumber == 223075) newStrategy = "GainOne";
200 if (not newStrategy.empty()) {
201 ATH_MSG_INFO( "Changing Gain Strategy to " << newStrategy);
202 gainStrategy = std::move(newStrategy);
203 }
204 if (!gainStrategy.empty() && consistent) {
205 m_isGain1 = (gainStrategy.find("GainOne") != std::string::npos);
206 m_isOvEmb = (gainStrategy.find("OvEmb") != std::string::npos);
207 m_isOvEmec = (gainStrategy.find("OvEmec") != std::string::npos);
208 m_isFcalLowEta = (gainStrategy.find("FcalLowEta") != std::string::npos);
209 m_isFcalHighEta = (gainStrategy.find("FcalHighEta") != std::string::npos);
210 } else if (gainStrategy == "") {
211 ATH_MSG_WARNING( "Gain Strategy collection empty" );
212 } else {
213 ATH_MSG_WARNING( "Inconsistent Gain Strategies" );
214 }
215 } else {
216 ATH_MSG_WARNING( "No Gain Strategy collection found" );
217 }
218 ATH_MSG_INFO( "isGain1 = " << m_isGain1
219 << ", isOvEmb = " << m_isOvEmb
220 << ", isOvEmec = " << m_isOvEmec
221 << ", isFcalLowEta = " << m_isFcalLowEta
222 << ", isFcalHighEta = " << m_isFcalHighEta );
223
225 m_rampDataContainer->setRunNumber(runNumber);
226 m_rampDataContainer->setGainStrategy(gainStrategy);
227 m_firstEvent = false;
228 }
229 else {
230 if (tts->size() != m_nTTs) {
231 // Adding missing towers, if any
232 ATH_MSG_WARNING("Number of trigger towers changed in event " << eventInfo->eventNumber()
233 << ": old=" << m_nTTs << ", new=" << tts->size());
234
235 unsigned int nmiss = 0;
236 for(auto* tt: *tts) {
237 bool isTile = m_xAODTTTools->isTile(*tt);
238 if (this->validTower(isTile)) {
239 if (m_rampDataContainer->rampData(tt->coolId()) == nullptr) {
240 m_rampDataContainer->addRampData(tt->coolId(),L1CaloRampData());
241 nmiss++;
242 }
243 }
244 }
245 ATH_MSG_WARNING("Added " << nmiss << " missing towers");
246 m_nTTs = tts->size();
247 }
248 }
249
250 // Reading L1Calo conditions
253
254 auto specialChannelRangeEnd = m_specialChannelRange.end();
255 bool nextStep = (m_nEvent % m_nEventsPerStep == 0);
256 for(auto *tt : *tts) {
257 // skip saturated towers
258 if(tt->isJepSaturated()) continue;
259
260 // isSaturated flag is not enough to check - test FADC for saturation, too
261 auto max = std::max_element(tt->adc().begin(), tt->adc().end());
262 if(*max >= m_fadcSaturationCut) continue;
263
264 // skip disabled channels
265 if(m_ttTool->disabledChannel(tt->coolId())) continue;
266
267 bool isTile = m_xAODTTTools->isTile(*tt);
268 if (this->validTower(isTile)) {
270 double level1Energy = getTriggerTowerEnergy(tt,pprChanCalib);
271 double caloEnergy = getCaloEnergy(tt);
272
273 // cut on 150 GeV ADC for Tile, lots of saturating calibration signals
274 if(isTile && level1Energy > m_tileSaturationCut) continue;
275
276 // see if we have a special channel and cut on level1 energy
277 auto specialChannelIt = m_specialChannelRange.find(tt->coolId());
278 if(specialChannelIt == specialChannelRangeEnd || level1Energy < specialChannelIt->second) {
279 ATH_MSG_DEBUG("Adding Energy for " << tt->coolId() << ":" << caloEnergy << " vs. " << level1Energy);
280 m_rampDataContainer->rampData(tt->coolId())->addData(caloEnergy, level1Energy);
281 } else {
282 // make sure we don't accidently miss the threshold again
283 specialChannelIt->second = -1000;
284 }
285 if(nextStep) m_rampDataContainer->rampData(tt->coolId())->nextStep();
286 }
287 }
288
289 ++m_nEvent;
290
291 return StatusCode::SUCCESS;
292}
293
295{
298 for(auto* tt: *tts) {
299 bool isTile = m_xAODTTTools->isTile(*tt);
300 if (this->validTower(isTile)) {
301 m_rampDataContainer->addRampData(tt->coolId(), rd);
302 }
303 }
304}
305
306// return E_T of cells comprising the trigger tower @c tt
308{
309 double et(0.);
310 auto id = m_ttTool->identifier(tt->eta(), tt->phi(), tt->sampling());
311
312 if(m_lvl1Helper->is_fcal(id)) {
313 if(tt->sampling() == 0) { // fcal em - use decorated value
314 et = ttCellsET(*tt);
315 } else { // had
316 LVL1::TriggerTowerKey K(tt->phi(), tt->eta());
317 LVL1::TriggerTower T(tt->phi(), tt->eta(), K.ttKey(tt->phi(), tt->eta()));
318 std::vector<float> etRec = m_jmTools->hadTTCellsEtByReceiver(&T);
319 if (etRec.size() == 2) {
320 if (m_isFcalLowEta) et = etRec[1];//FCAL high and low eta receivers swapped here due to LAr baseplane misrouting
321 else if (m_isFcalHighEta) et = etRec[0];
322 else et = etRec[0] + etRec[1];
323 } else if (etRec.size() == 1) et = etRec[0];
324 }
325 } else {
326 if(m_lvl1Helper->is_barrel_end(id) && (m_isOvEmb || m_isOvEmec)) {
327 LVL1::TriggerTowerKey K(tt->phi(), tt->eta());
328 LVL1::TriggerTower T(tt->phi(), tt->eta(), K.ttKey(tt->phi(), tt->eta()));
329 std::vector<float> energyRec = m_jmTools->emTTCellsEnergyByReceiver(&T);
330 if (energyRec.size() == 2) {
331 double energy(0.);
332 if (m_isOvEmec) energy = energyRec[0];
333 else energy = energyRec[1];
334 et = energy / std::cosh(tt->eta());
335 } else et = energyRec[0] / std::cosh(tt->eta());
336 } else {
337 et = ttCellsEnergy(*tt) / std::cosh(tt->eta());
338 }
339 }
340 return et;
341}
342
343// calculate trigger tower E_T from adc values
344// if run is with gain 1 loaded, need special treatment of E_T for HEC and TILE
346 // calibration is against ADC energy "(adc peak value - pedestal) / 4"
347 auto max = std::max_element(tt->adc().begin(), tt->adc().end());
348
349 if(!pprChanCalib->pprChanCalib(tt->coolId())) {
350 ATH_MSG_WARNING("Empty PPrChanCalib for 0x "
351 << std::hex << tt->coolId() << std::dec << "!");
352 return 0.;
353 }
354
355 double energy = (*max - int( pprChanCalib->pprChanCalib(tt->coolId())->pedValue())) * 0.25;
356 ATH_MSG_DEBUG("PedValue " << tt->coolId() << ":" << int( pprChanCalib->pprChanCalib(tt->coolId())->pedValue()) );
357
358
359 if (energy < 0.) energy = 0.;
360
361 // no corrections if gain is set correctly
362 if(!m_isGain1) return energy;
363
364 // correct hec and tile if gain 1
365 auto id = m_ttTool->identifier(tt->eta(), tt->phi(), tt->sampling());
366 if(m_lvl1Helper->is_hec(id)) {
367 energy /= std::cosh(tt->eta());
368 if(fabs(tt->eta()) > 2.5) {
369 energy *= 10.;
370 } else if(fabs(tt->eta()) > 1.9) {
371 energy *= 5.;
372 } else {
373 energy *= 3.125;
374 }
375 } else if(m_lvl1Helper->is_tile(id)) {
376 energy /= std::cosh(tt->eta());
377 }
378
379 return energy;
380}
381
382// function fills a map of cooldid -> (number of cells failing quality, avg. cell timing)
383// used for fcal debugging
385 const std::vector<const CaloCell*>& cells(m_xAODTTTools->getCaloCells(*tt));
386 double oneOverNCells = 1./double(cells.size());
387 for(const auto *cell : cells) {
388 auto it = m_mapBadOFCIteration.find(tt->coolId());
389 if(it == m_mapBadOFCIteration.end()) {
390 m_mapBadOFCIteration.insert(std::make_pair(tt->coolId(), std::make_pair(!(cell->provenance() & 0x100),
391 (cell->time()*oneOverNCells))));
392 continue;
393 }
394 if(!(cell->provenance() & 0x100)) {
395 it->second.first += 1;
396 }
397 it->second.second += (cell->time()*oneOverNCells);
398 }
399}
400
401bool L1CaloRampMaker::validTower(const bool& isTile) {
402 return ((m_doLAr && !isTile) || (m_doTile && isTile));
403}
404
406{
408
410 std::ofstream bad_ofciter("bad-ofciter.txt");
411 std::map<unsigned int, std::pair<unsigned int, double> >::const_iterator it(m_mapBadOFCIteration.begin()), itE(m_mapBadOFCIteration.end());
412 for(;it != itE; ++it) {
413 bad_ofciter << "0x" << std::hex << it->first << " "
414 << std::dec << double(it->second.first) / double(m_nEvent)
415 << " " << it->second.second / double(m_nEvent) << std::endl;
416 }
417 bad_ofciter.close();
418 }
419
420 return StatusCode::SUCCESS;
421}
422
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
This file defines the class for a collection of AttributeLists where each one is associated with a ch...
Helpers for checking error return status codes and reporting errors.
#define CHECK(...)
Evaluate an expression and check for errors.
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
float et(const xAOD::jFexSRJetRoI *j)
static Double_t sc
#define max(a, b)
Definition cfImp.cxx:41
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
const ServiceHandle< StoreGateSvc > & detStore() const
Container class for CaloCell.
This class initializes the Calo (LAr and Tile) offline identifiers.
const CaloLVL1_ID * getLVL1_ID(void) const
This class is a collection of AttributeLists where each one is associated with a channel number.
const_iterator end() const
const_iterator begin() const
Access to Chan/AttributeList pairs via iterators.
ChanAttrListMap::const_iterator const_iterator
size_type size() const noexcept
Returns the number of elements in the collection.
Container of L1CaloRampData objects.
Transient class to store the RampData calculated from calibration runs.
ToolHandle< LVL1::IL1CaloxAODOfflineTriggerTowerTools > m_xAODTTTools
const CaloLVL1_ID * m_lvl1Helper
double getCaloEnergy(const xAOD::TriggerTower *tt)
std::string m_gainStrategyFolder
ToolHandle< LVL1::IL1CaloOfflineTriggerTowerTools > m_jmTools
std::string m_triggerTowerContainerName
std::map< unsigned int, std::pair< unsigned int, double > > m_mapBadOFCIteration
std::unique_ptr< L1CaloRampDataContainer > m_rampDataContainer
SG::ReadCondHandleKey< CondAttrListCollection > m_strategy
unsigned int m_nTTs
StatusCode initialize()
bool validTower(const bool &isTile)
SG::ReadHandleKey< CaloCellContainer > m_caloCellsKey
L1CaloRampMaker(const std::string &name, ISvcLocator *pSvcLocator)
StatusCode finalize()
unsigned int m_nEventsPerStep
std::string m_outputFolderName
void setupRampDataContainer(const xAOD::TriggerTowerContainer *triggerTowerContainer)
double getTriggerTowerEnergy(const xAOD::TriggerTower *tt, SG::ReadCondHandle< L1CaloPprChanCalibContainer > pprCond)
void checkProvenance(const xAOD::TriggerTower *tt)
ToolHandle< LVL1::IL1TriggerTowerToolRun3 > m_ttTool
unsigned int m_nEvent
virtual ~L1CaloRampMaker()
SG::ReadCondHandleKey< L1CaloPprChanCalibContainer > m_pprChanCalibContainer
SG::ReadCondHandleKey< L1CaloPprDisabledChannelContainerRun2 > m_pprDisabledChannelContainer
SG::ReadCondHandleKey< LArOnOffIdMapping > m_cablingKey
std::map< int, int > m_specialChannelRange
unsigned int m_nSteps
The TriggerTowerKey object provides the key for each trigger tower depending on its eta-phi coords.
virtual unsigned int ttKey(const TriggerTower &tower)
returns the key of the passed tower
Trigger towers are the inputs to all other parts of the calorimeter trigger.
SG::ConstAccessor< T, ALLOC > ConstAccessor
Helper class to provide type-safe access to aux data.
Definition AuxElement.h:131
uint32_t runNumber() const
The current event's run number.
uint64_t eventNumber() const
The current event's event number.
eFexTowerBuilder creates xAOD::eFexTowerContainer from supercells (LATOME) and triggerTowers (TREX) i...
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.
Extra patterns decribing particle interation process.