ATLAS Offline Software
Loading...
Searching...
No Matches
EfexInputMonitorAlgorithm.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#include "TTree.h"
8#include "TFile.h"
9
10EfexInputMonitorAlgorithm::EfexInputMonitorAlgorithm( const std::string& name, ISvcLocator* pSvcLocator )
11 : AthMonitorAlgorithm(name,pSvcLocator)
12{
13}
14
16
17 ATH_MSG_DEBUG("EfexInputMonitorAlgorith::initialize");
18 ATH_MSG_DEBUG("Package Name "<< m_packageName);
19 ATH_MSG_DEBUG("m_eFexTowerContainer"<< m_eFexTowerContainerKey);
20
21 // we initialise all the containers that we need
22 ATH_CHECK( m_eFexTowerContainerKey.initialize() );
24
25 ATH_CHECK( m_bcContKey.initialize() );
26
27
28 // load the scid map
29 if (auto fileName = PathResolverFindCalibFile( "L1CaloFEXByteStream/2023-02-13/scToEfexTowers.root" ); !fileName.empty()) {
30 std::unique_ptr<TFile> f( TFile::Open(fileName.c_str()) );
31 if (f) {
32 TTree* t = f->Get<TTree>("mapping");
33 if(t) {
34 unsigned long long scid = 0;
35 std::pair<int,int> coord = {0,0};
36 std::pair<int,int> slot;
37 t->SetBranchAddress("scid",&scid);
38 t->SetBranchAddress("etaIndex",&coord.first);
39 t->SetBranchAddress("phiIndex",&coord.second);
40 t->SetBranchAddress("slot1",&slot.first);
41 t->SetBranchAddress("slot2",&slot.second);
42 for(Long64_t i=0;i<t->GetEntries();i++) {
43 t->GetEntry(i);
44 m_scMap[std::make_pair(coord,slot.first)].first.insert(scid);
45 m_scMap[std::make_pair(coord,slot.second)].first.insert(scid);
46 }
47 // now convert scid list to list of strings
48 for(auto& [key,scs] : m_scMap) {
49 std::stringstream s;
50 for(auto id : scs.first) {
51 s << (id>>32) << ",";
52 }
53 scs.second = s.str();
54 scs.first.clear(); // not needed any more, so clear it
55 }
56 }
57 }
58 }
59
60
61
62
64}
65
66StatusCode EfexInputMonitorAlgorithm::fillHistograms( const EventContext& ctx ) const {
67
68 ATH_MSG_DEBUG("EfexInputMonitorAlgorithm::fillHistograms");
69
70 // Access eFex eTower container - should always have a collection, even if empty
72 if(!eFexTowerContainer.isValid()){
73 ATH_MSG_ERROR("No eFex Tower container found in storegate "<< m_eFexTowerContainerKey);
74 return StatusCode::FAILURE;
75 }
76
77
78 auto evtNumber = Monitored::Scalar<ULong64_t>("EventNumber",GetEventInfo(ctx)->eventNumber());
79 auto lbnString = Monitored::Scalar<std::string>("LBNString",std::to_string(GetEventInfo(ctx)->lumiBlock()));
80 auto lbn = Monitored::Scalar<int>("LBN",GetEventInfo(ctx)->lumiBlock());
81
82 // mismatches can be caused by recent/imminent OTF maskings, so track timings
83 auto timeSince = Monitored::Scalar<int>("timeSince", -1);
84 auto timeUntil = Monitored::Scalar<int>("timeUntil", -1);
85 auto timeUntilCapped = Monitored::Scalar<int>("timeUntilCapped", -1); // capped at 199 for histograms
87 if(larBadChan.isValid()) {
88 timeSince = ctx.eventID().time_stamp() - larBadChan.getRange().start().time_stamp();
89 timeUntil = larBadChan.getRange().stop().time_stamp() - ctx.eventID().time_stamp();
90 timeUntilCapped = std::min(int(timeUntil),199);
91 }
93 auto ErrorAndLocation = Monitored::Scalar<std::string>("ErrorAndLocation","");
94
95 auto TowerId = Monitored::Scalar<int32_t>("TowerId",0);
96 auto Towereta = Monitored::Scalar<float>("TowerEta",0.0);
97 auto Towerphi = Monitored::Scalar<float>("TowerPhi",0.0);
98 auto TowerRefCount = Monitored::Scalar<int>("RefTowerCount",0);
99 auto Toweremstatus = Monitored::Scalar<uint32_t>("TowerEmstatus",0);
100 auto Towerhadstatus = Monitored::Scalar<uint32_t>("TowerHadstatus",0);
101 auto TowerSlot = Monitored::Scalar<int32_t>("TowerSlot",0);
102 auto TowerCount = Monitored::Scalar<int>("TowerCount",0);
103 auto SlotSCID = Monitored::Scalar<std::string>("SlotSCID","");
104
105 // first test dataTowers not empty unless prescaled event
106 bool isPrescaled = (((GetEventInfo(ctx)->extendedLevel1ID()&0xffffff) % 200) != 0);
107 size_t badTowers = 0;
108 if(!isPrescaled && eFexTowerContainer->empty()) {
109 Decision = "MissingDataTowers";
110 fill("errors", Decision,timeSince,timeUntil,evtNumber,lbn,lbnString,TowerId,Towereta,Towerphi,Toweremstatus,Towerhadstatus,TowerSlot,TowerCount,TowerRefCount,SlotSCID);
111 } else if(isPrescaled && !eFexTowerContainer->empty()) {
112 // check if all the towers have errors, if so then this readout IS expected
113 for(auto eFexTower : *eFexTowerContainer) {
114 if(eFexTower->em_status()||eFexTower->had_status()) badTowers++;
115 }
116 if(badTowers != eFexTowerContainer->size()) {
117 Decision = "UnexpectedDataTowers";
118 fill("errors", Decision, timeSince, timeUntil, evtNumber, lbn, lbnString, TowerId, Towereta, Towerphi,
119 Toweremstatus, Towerhadstatus, TowerSlot, TowerCount, TowerRefCount, SlotSCID);
120 }
121 }
122
123 if(eFexTowerContainer->empty() || badTowers==eFexTowerContainer->size()) return StatusCode::SUCCESS; // don't do the rest of the monitoring unless processing a DataTowers event
124
125
126 // Access eFexTower ref container, if possible
128 auto etaIndex = [](float eta) { return int( eta*10 ) + ((eta<0) ? -1 : 1); };
129 auto phiIndex = [](float phi) { return int( phi*32./M_PI ) + (phi<0 ? -1 : 1); };
130 std::map<std::pair<int,int>,const xAOD::eFexTower*> refTowers;
131 size_t missingSlots = 0;
132 if (eFexTowerContainerRef.isValid()) {
133 if(eFexTowerContainerRef->empty()) missingSlots=34048;
134 for (auto eTower: *eFexTowerContainerRef) {
135 refTowers[std::pair(etaIndex(eTower->eta() + 0.025), phiIndex(eTower->phi() + 0.025))] = eTower;
136 // fill profile histograms for each layer (ECAL,HCAL) so that we can identify when a layer is being noisy
137 Towereta = eTower->eta(); Towerphi = eTower->phi();
138 std::vector<uint16_t> Toweret_count=eTower->et_count();
139 for(size_t i=0;i<Toweret_count.size();i++) {
140 TowerRefCount = Toweret_count[i];
141 if (TowerRefCount==1025) missingSlots+=1; // 1025 comes from eFexTowerBuilder if it had no supercells
142 if(TowerRefCount==1025 || TowerRefCount==1022) TowerRefCount=0; // unavailable or invalid code
143 fill((i<10) ? "ecal" : "hcal",lbn,Towereta,Towerphi,TowerRefCount);
144 }
145 }
146 }
147 if(missingSlots > 1280) { /*expect 1280 unfilled slots in a normal event*/
148 Decision = "MissingSCells";
149 fill("errors", Decision,timeSince,timeUntil,evtNumber,lbn,lbnString,TowerId,Towereta,Towerphi,Toweremstatus,Towerhadstatus,TowerSlot,TowerCount,TowerRefCount,SlotSCID);
150 ATH_MSG_WARNING(std::string(Decision) << " in event " << evtNumber << " in lb " << std::string(lbnString));
151 }
152
153
154
155 std::set<std::pair<std::pair<int,int>,int>> doneCounts; // only fill each count once (there are duplicates in DataTowers readout b.c. of module overlap)
156
157 auto IsMonReady = Monitored::Scalar<bool>("IsMonReady",true); // used to fill into eta/phi map only certain types of error.
158 auto OnPed = Monitored::Scalar<double>("OnPedestal",0.);
159 auto AboveCut = Monitored::Scalar<bool>("AboveCut",false);
160 auto BelowCut = Monitored::Scalar<bool>("BelowCut",false);
161 auto binNumber = Monitored::Scalar<int>("binNumber",0);
162
163 std::set<std::string> reportedErrors;
164
165 for(const xAOD::eFexTower* eTower : *eFexTowerContainer) {
166 TowerId = eTower->id();
167 Towereta=eTower->eta();
168 Towerphi=eTower->phi();
169 Toweremstatus=eTower->em_status();
170 Towerhadstatus=eTower->had_status();
171 if(eTower->em_status()) {
172 Decision="BadEMStatus";
173 ErrorAndLocation = "#splitline{" + static_cast<std::string>(Decision) + "}{" + std::to_string(TowerId) + "}";
174 fill("errors",Decision,ErrorAndLocation,timeSince,timeUntil,evtNumber,lbn,lbnString,TowerId,Towereta,Towerphi,Toweremstatus,Towerhadstatus,TowerSlot,TowerCount,TowerRefCount,SlotSCID,IsMonReady);
175 if(!reportedErrors.count(Decision)) {
176 ATH_MSG_WARNING(std::string(Decision) << " in event " << evtNumber << " in lb " << std::string(lbnString));
177 reportedErrors.insert(Decision);
178 }
179 }
180 if(eTower->had_status()) {
181 Decision="BadHadStatus";
182 ErrorAndLocation = "#splitline{" + static_cast<std::string>(Decision) + "}{" + std::to_string(TowerId) + "}";
183 fill("errors",Decision,ErrorAndLocation,timeSince,timeUntil,evtNumber,lbn,lbnString,TowerId,Towereta,Towerphi,Toweremstatus,Towerhadstatus,TowerSlot,TowerCount,TowerRefCount,SlotSCID,IsMonReady);
184 if(!reportedErrors.count(Decision)) {
185 ATH_MSG_WARNING(std::string(Decision) << " in event " << evtNumber << " in lb " << std::string(lbnString));
186 reportedErrors.insert(Decision);
187 }
188 }
189 std::vector<uint16_t> counts=eTower->et_count();
190 std::vector<uint16_t> refcounts;
191 auto coord = std::pair(etaIndex(eTower->eta() + 0.025), phiIndex(eTower->phi() + 0.025));
192 if(!refTowers.empty()) {
193 if(auto itr = refTowers.find(coord); itr != refTowers.end()) {
194 refcounts = itr->second->et_count();
195 }
196 }
197 for(size_t i=0;i<counts.size();i++) {
198 if (eTower->disconnectedCount(i)) continue; // skip disconnected counts
199 // only do each tower once (skip duplications across modules)
200 if (doneCounts.find(std::pair(coord,i))==doneCounts.end()) {
201 doneCounts.insert(std::pair(coord,i));
202 } else {
203 continue;
204 }
205 bool isLAr = !(i==10 && std::abs(Towereta)<=1.5);
206 if(counts[i]==1025) {
207 // 1025 is the code used by bytestream decoder if there is no input for that slot
208 if(isLAr) {
209 if (auto itr = m_scMap.find(std::make_pair(coord, i)); itr != m_scMap.end()) {
210 SlotSCID = itr->second.second;
211 }
212 Decision = "MissingLAr";
213 fill("errors", Decision,timeSince,timeUntil,evtNumber,lbn,lbnString,TowerId,Towereta,Towerphi,Toweremstatus,Towerhadstatus,TowerSlot,TowerCount,TowerRefCount,SlotSCID,IsMonReady);
214 if(!reportedErrors.count(Decision)) {
215 ATH_MSG_WARNING(std::string(Decision) << " in event " << evtNumber << " in lb " << std::string(lbnString));
216 reportedErrors.insert(Decision);
217 }
218 } else {
219 Decision = "MissingTile";
220 SlotSCID="";
221 fill("errors", Decision,timeSince,timeUntil,evtNumber,lbn,lbnString,TowerId,Towereta,Towerphi,Toweremstatus,Towerhadstatus,TowerSlot,TowerCount,TowerRefCount,SlotSCID,IsMonReady);
222 if(!reportedErrors.count(Decision)) {
223 ATH_MSG_WARNING(std::string(Decision) << " in event " << evtNumber << " in lb " << std::string(lbnString));
224 reportedErrors.insert(Decision);
225 }
226 }
227 continue;
228 }
229 TowerSlot = i;
230 TowerCount = counts[i];
231 TowerRefCount = -1;
232 Decision = "";
233 if(!refTowers.empty()) { // only do slot-by-slot comparison if we actually have ref towers
234 if(refcounts.size() != counts.size()) {
235 Decision = "NumSlotMismatch";
236 } else {
237 TowerRefCount = refcounts.at(i);
238 if(isLAr) {
239 if(TowerCount==1022) {
240 //Decision = "LArInvalidCode"; - not an error, or at least not one we (L1Calo) should be tracking for now
241 if(TowerRefCount!=1022) {
242 Decision = "LArInvalidCodeMismatched";
243 }
244 } else if(!TowerCount && TowerRefCount) {
245 Decision="LArMissingMask";
246 } else if(TowerCount && !TowerRefCount) {
247 Decision="LArExtraMask";
248 } else if(TowerCount != TowerRefCount) {
249 if(TowerRefCount==1025) {
250 Decision = "MissingRefLAr";
251 } else {
252 Decision = "LArMismatch";
253 }
254 }
255 // should we also monitor saturations (code 1023?)
256 } else if(TowerCount != TowerRefCount) {
257 if(TowerRefCount==1025) {
258 Decision = "MissingRefTile";
259 } else {
260 Decision="TileMismatch";
261 }
262 }
263 }
264 if(!std::string(Decision).empty()) {
265 if(isLAr) {
266 if (auto itr = m_scMap.find(std::make_pair(coord, i)); itr != m_scMap.end()) {
267 SlotSCID = itr->second.second;
268 }
269 }
270 if(!(isLAr && timeUntil>=0 && timeUntil<=5)) { // lar errors within 5s of an otf masking update are not treated as errors
271 ErrorAndLocation = "#splitline{" + static_cast<std::string>(Decision) + "}{" + std::to_string(TowerId) + "}";
272 fill("errors", Decision, ErrorAndLocation, timeSince, timeUntil, evtNumber, lbn, lbnString,
273 TowerId, Towereta, Towerphi, Toweremstatus, Towerhadstatus, TowerSlot, TowerCount,
274 TowerRefCount, SlotSCID,IsMonReady);
275 if (!reportedErrors.count(Decision)) {
276 ATH_MSG_WARNING(std::string(Decision) << " in event " << evtNumber << " in lb "
277 << std::string(lbnString));
278 reportedErrors.insert(Decision);
279 }
280 }
281 }
282 }
283 // since lar invalid codes will be treated as a 0 energy, don't fill into plot
284 if ((!isLAr) || (TowerCount != 1022)) {
285 AboveCut = (TowerCount >= (isLAr ? 52:1)); // count of 52 ~= 500 MeV
286 BelowCut = (TowerCount < (isLAr ? 23:0) && TowerCount>0); // count of 22 ~= -500 MeV
287 if(AboveCut || BelowCut) {
288 int etaIdx = TowerId/100000;
289 if(etaIdx>0) etaIdx--; // so goes from -25 to 24
290 int phiIdx = std::abs(TowerId % 100000)/1000;
291 if(phiIdx>31) phiIdx -= 64; // so goes from -32 to 31
292 binNumber = (25 + etaIdx)*64 + phiIdx+33; // = 64*(x-1)+y as displayed in standard histogram
293 fill((i<10) ? "ecal" : "hcal",lbn,Towereta,Towerphi,TowerCount,AboveCut,BelowCut,binNumber);
294 }
295 }
296 }
297 }
298
299
300 return StatusCode::SUCCESS;
301}
302
303
#define M_PI
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
double coord
Type of coordination system.
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
static const Attributes_t empty
virtual StatusCode initialize() override
initialize
SG::ReadHandle< xAOD::EventInfo > GetEventInfo(const EventContext &) const
Return a ReadHandle for an EventInfo object (get run/event numbers, etc.)
AthMonitorAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
size_type size() const noexcept
Returns the number of elements in the collection.
bool empty() const noexcept
Returns true if the collection is empty.
virtual StatusCode fillHistograms(const EventContext &ctx) const override
adds event to the monitoring histograms
SG::ReadHandleKey< xAOD::eFexTowerContainer > m_eFexTowerContainerKey
EfexInputMonitorAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
std::map< std::pair< std::pair< int, int >, int >, std::pair< std::set< unsigned long long >, std::string > > m_scMap
SG::ReadCondHandleKey< LArBadChannelCont > m_bcContKey
SG::ReadHandleKey< xAOD::eFexTowerContainer > m_eFexTowerContainerRefKey
virtual StatusCode initialize() override
initialize
Declare a monitored scalar variable.
const EventIDRange & getRange()
virtual bool isValid() override final
Can the handle be successfully dereferenced?
uint32_t em_status() const
get em status bit
uint32_t had_status() const
setter for the above
eFexTower_v1 eFexTower
Define the latest version of the TriggerTower class.
Definition eFexTower.h:15
void fill(H5::Group &out_file, size_t iterations)