ATLAS Offline Software
Loading...
Searching...
No Matches
PPMSimBSMonitorAlgorithm.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
8
9PPMSimBSMonitorAlgorithm::PPMSimBSMonitorAlgorithm( const std::string& name, ISvcLocator* pSvcLocator )
10 : AthMonitorAlgorithm(name,pSvcLocator)
11{
12}
13
15
16 ATH_MSG_DEBUG("PPMSimBSMonitorAlgorithm::initialize");
17 ATH_MSG_DEBUG("Package Name "<< m_packageName);
18 ATH_MSG_DEBUG("m_xAODTriggerTowerContainerName "<< m_xAODTriggerTowerContainerName);
19
20 // we initialise all the containers that we need
23
24
25 ATH_CHECK( m_ttTool.retrieve());
26 ATH_CHECK( m_runParametersContainer.initialize() );
27
28 ATH_CHECK(m_errorLocation.initialize());
29
30 return StatusCode::SUCCESS;
31}
32
33StatusCode PPMSimBSMonitorAlgorithm::fillHistograms( const EventContext& ctx ) const {
34
35 ATH_MSG_DEBUG("PPMSimBSMonitorAlgorithm::fillHistograms");
36
37
38 // Retrieve L1CaloRunParametersContainer
40 unsigned int readoutConfigID = runParameters->runParameters(1)->readoutConfigID();
41 ATH_MSG_DEBUG("RunParameters:: readoutConfigID " << readoutConfigID);
42
43 // Retrieve Trigger Towers from SG
45 if(!triggerTowerTES.isValid()){
46 ATH_MSG_ERROR("No Trigger Tower container found in TES "<< m_xAODTriggerTowerContainerName);
47 return StatusCode::FAILURE;
48 }
49
50 // Create a vector of trigger towers with quantities to be monitored
51 std::vector<MonitorTT> vecMonTT; // All towers
52
53 const int nCrates = 8;
54 ErrorVector crateError(nCrates);
55 ErrorVector moduleError(nCrates);
56
57 bool error_tt{false};
58
59 // PPM sim vectors
60 std::vector<int> LutCp;
61 std::vector<int> LutJep;
62 std::vector<int> BcidR;
63 std::vector<int> BcidD;
64
65 // Loop over trigger tower container
66 // Create the trigger tower objects and calculate scaled phi
67 for (const xAOD::TriggerTower* tt : *triggerTowerTES) {
68 ATH_CHECK( makePPMTower(tt, vecMonTT) );
69 }
70
71
72 std::vector<std::string> mismatch_map= {"NonZeroMatches", "ZeroMatches", "DataNoSim", "SimNoData"};
73 std::vector<std::string> lut_map= { "SimEqData", "SimNeData", "SimNoData", "DataNoSim"};
74 std::vector<std::string> crate_map= { "cr0cr1", "cr2cr3", "cr4cr5", "cr6cr7"};
75
76 // set maximum number of error events per lumiblock(per type) to avoid histograms with many x-bins
77 const int maxErrorsPerLB=10;
78
79 auto lb = GetEventInfo(ctx)->lumiBlock();
80 ATH_MSG_DEBUG("Lumi Block" << lb);
81 const long long eventNumber = ctx.eventID().event_number();
82 ATH_MSG_DEBUG("Event Number" << eventNumber);
83
84
85
86 // Loop over the trigger tower objects and fill the histograms
87
88 for (auto& myTower : vecMonTT) {
89 ATH_MSG_DEBUG("PPMSimBSMonitorAlgorithm looping over TTs");
90 const L1CaloCoolChannelId coolId((myTower.tower)->coolId());
91 const int datCp = (myTower.tower)->cpET();
92 const int datJep = (myTower.tower)->lut_jep().empty() ? 0 : (myTower.tower)->jepET();
93 bool pedCorrOverflow = false;
94 const std::size_t nPedCorr = (myTower.tower)->correction().size();
95 int simCp = 0;
96 int simJep = 0;
97 int simBcid = 0;
98 uint8_t datBcid = 0;
99 std::vector<uint8_t> datBcidVec = ( (myTower.tower)->bcidVec());
100 if ( datBcidVec.size() > 0) {
101 datBcid = datBcidVec[ (myTower.tower)->peak()];
102 }
103
104
105
106 //Retrieve RunParameters container from COOL database and check if run was taken with 80MHz readout. If yes, drop the 80MHz samples to emulate 40 MHz readout
107 std::vector<uint16_t> digits40;
108
109 if(readoutConfigID==5 or readoutConfigID==6){
110
111 int nSlices = (myTower.tower)->adc().size();
112
113 if((nSlices%4)==3){
114 for (int i=0 ; i < (nSlices-1)/2 ; i++ ){
115 digits40.push_back((myTower.tower)->adc().at(2*i+1));
116 }
117 }
118 else if((nSlices%4)==1){
119 for (int i=0 ; i <= (nSlices-1)/2 ; i++ ){
120 digits40.push_back((myTower.tower)->adc().at(2*i));
121 }
122 }
123
124 }else{
125 digits40 = (myTower.tower)->adc();
126 }
127
128 const std::vector<uint_least16_t>& ADC = digits40;
129 const int Slices = ADC.size();
130 const int Peak = Slices/2.;
131
132 //Check for over-/underflow of pedestalCorrection
133 for(std::size_t i = 0; i < nPedCorr; ++i) {
134 if((myTower.tower)->correction()[i]>=511 or (myTower.tower)->correction()[i]<=-512){
135 pedCorrOverflow = true;
136 break;
137 }
138 }
139
140
141 // only run simulation for non-empty TTs
142 if(datCp || datJep || *std::max_element(std::begin(ADC), std::end(ADC)) >= m_simulationADCCut) {
143 BcidR.clear();
144 BcidD.clear();
145 m_ttTool->simulateChannel(*(myTower.tower), LutCp, LutJep, BcidR, BcidD);
146 simBcid = BcidR[Peak];
147 if (Slices < 7 || nPedCorr < 3) {
148 simJep = LutJep[Peak];
149 simCp = LutCp[Peak];
150 }
151 }
152
153
154
155 // ---------------------Fill in error plots------------------------
156 int mismatch = 0;
157
158 std::string groupName = "group_Mismatch_peakf_";
159
160 if (datCp || datJep || *std::max_element(std::begin(ADC), std::end(ADC)) >= m_simulationADCCut) {
161 std::bitset<3> simBcidBits(simBcid);
162 std::bitset<3> datBcidBits(datBcid);
163 if ((Slices >= 7) && (nPedCorr >= 3)) { // compare simulation of peak finder to data (sim not possible in 5+1 readout mode)
164 if (simBcidBits[2] && datBcidBits[2]) { //non-zero match
165 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + mismatch_map.at(0), "", 1) );
166 }
167 else if (!simBcidBits[2] && !datBcidBits[2]) { // zero match
168 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + mismatch_map.at(1), "", 1) );
169 }
170 else if (simBcidBits[2] != datBcidBits[2]) { // mismatch
171 mismatch = 1;
172 if (!simBcidBits[2]) { //data no sim
173 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + mismatch_map.at(2), "", 1) );
174 }
175 else if (!datBcidBits[2]) { //sim no data
176 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + mismatch_map.at(3), "", 1) );
177 }
178 if (mismatch>0) {
179 ATH_MSG_DEBUG("PeakfinderBCID sim/data Mismatch coolId/sim/dat: "
180 << std::hex <<coolId.id() << std::dec << "/" << simBcidBits[2] << "/" << datBcidBits[2]);
181 }
182 }
183 }
184
185
186
187 groupName = "group_Mismatch_satBcid_";
188
189 if (ADC[0] < 1020 && ADC[1] < 1020) { // compare simulation of saturated bcid algorithm to data
190 if (simBcidBits[1] && datBcidBits[1]) { // non-zero match
191 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + mismatch_map.at(0), "", 1) );
192 }
193 else if (!simBcidBits[1] && !datBcidBits[1]) { // zero match
194 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + mismatch_map.at(1), "", 1) );
195 }
196 else if (simBcidBits[1] != datBcidBits[1]) { // mismatch
197 mismatch = 1;
198 if (!simBcidBits[1]) { // data no sim
199 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + mismatch_map.at(2), "", 1) );
200 mismatch=0;
201 }
202 else if (!datBcidBits[1]) { // sim no data
203 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + mismatch_map.at(3), "", 1) );
204 }
205 if (mismatch>0) {
206 ATH_MSG_DEBUG("SaturatedBCID sim/data Mismatch coolId/sim/dat: "
207 << std::hex <<coolId.id() << std::dec << "/" << simBcidBits[1] << "/" << datBcidBits[1]);
208 }
209 }
210 }
211 }
212
213
214 // Compare LUT simulation to data
215 // only fill histograms for non-empty towers (simulation or data)
216 if (!simCp && !datCp && !simJep && !datJep) continue;
217
218
219 groupName = "groupLUTCP_EM_";
220 if ( (myTower.tower)->layer() == 0) { // For EM layer
221 // For LUT-CP
222 if (simCp && simCp == datCp) { // non-zero match
223 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(0), "", 1) );
224 }
225 else if (simCp != datCp && !pedCorrOverflow) { // mis-match
226 mismatch = 1;
227 if (simCp && datCp) { // non-zero mis-match
228 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(1), "", 1) );
229 }
230 else if (!datCp) { // no data
231 if ((Slices >= 7) && (nPedCorr >= 3)) {
232 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(2), "", 1) );
233 }
234 else mismatch = 0;
235 }
236 else { // no sim
237 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(3), "", 1) );
238 }
239 if (mismatch>0) {
240 ATH_MSG_DEBUG("EMTowerMismatch coolId/simCp/datCp: "
241 << std::hex <<coolId.id() << std::dec << "/" << simCp << "/" << datCp);
242 }
243 }
244
245
246 groupName = "groupLUTJEP_EM_";
247
248 if (simJep && simJep == datJep) { // non-zero match
249 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(0), "", 1) );
250 }
251 else if (simJep != datJep && !pedCorrOverflow) { // mis-match
252 mismatch = 1;
253 if (simJep && datJep) { // non-zero mis-match
254 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(1), "", 1) );
255 }
256 else if (!datJep) { // no data
257 if ((Slices >= 7) && (nPedCorr >= 3)) {
258 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(2), "", 1) );
259 }
260 else mismatch = 0;
261 }
262 else {
263 // no sim
264 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(3), "", 1) );
265 }
266 if (mismatch>0) {
267 ATH_MSG_DEBUG("EMTowerMismatch coolId/simJep/datJep: "
268 << std::hex <<coolId.id() << std::dec << "/" << simJep << "/" << datJep);
269 }
270 }
271 }
272
273
274 // For HAD layer
275 groupName = "groupLUTCP_HAD_";
276
277 if ((myTower.tower)->layer() == 1) { // For HAD layer
278 // For LUT-CP
279 if (simCp && simCp == datCp) { // non-zero match
280 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(0), "", 1) );
281 }
282 else if (simCp != datCp && !pedCorrOverflow ) { // mis-match
283 mismatch = 1;
284 if (simCp && datCp) { // non-zero mis-match
285 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(1), "", 1) );
286 }
287 else if (!datCp) { // no data
288 if ((Slices >= 7) && (nPedCorr >= 3)) {
289 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(2), "", 1) );
290 }
291 else mismatch = 0;
292 }
293 else { // no sim
294 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(3), "", 1) );
295 }
296 if (mismatch>0) {
297 ATH_MSG_DEBUG("HADTowerMismatch coolId/simCp/datCp: "
298 << std::hex <<coolId.id() << std::dec << "/" << simCp << "/" << datCp);
299 }
300 }
301
302 // For LUT-JEP
303 groupName = "groupLUTJEP_HAD_";
304
305 if (simJep && simJep == datJep) { // non-zero match
306 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(0), "", 1) );
307 }
308 else if (simJep != datJep && !pedCorrOverflow ) { // mis-match
309 mismatch = 1;
310 if (simJep && datJep) { // non-zero mis-match
311 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(1), "", 1) );
312 }
313 else if (!datJep) { // no data
314 if ((Slices >= 7) && (nPedCorr >= 3)) {
315 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(2), "", 1) );
316 }
317 else mismatch = 0;
318 }
319 else { // no sim
320 ATH_CHECK( fillPPMEtaPhi(myTower, groupName + lut_map.at(3), "", 1) );
321
322 }
323 if (mismatch>0) {
324 ATH_MSG_DEBUG("HADTowerMismatch coolId/simJep/datJep: "
325 << std::hex <<coolId.id() << std::dec << "/" << simJep << "/" << datJep);
326 }
327 }
328 }
329
330
331
332
333
334 groupName = "group_Error_";
335
336
337 // scope for mutable error event per lumi block tt counter
338
339
340
341 if (mismatch == 1) {
342 std::lock_guard<std::mutex> lock(m_mutex);
343 const int crate = coolId.crate();
344 const int module = coolId.module();
345 crateError.at(crate) = 1;
346 if (!error_tt) {
347 m_errorLB_tt_counter[lb]+=1;
348 error_tt = true;
349 }
350 if (!((moduleError.at(crate) >> module) & 0x1)) {
351 const int y = module + 16 * (crate % 2);
352 auto y_2D = Monitored::Scalar<int>("y_2D", y);
353 if (m_errorLB_tt_counter[lb]<=maxErrorsPerLB) {
354 auto eventMonitor= Monitored::Scalar<std::string>("eventMonitor", std::to_string(eventNumber));
355 if (crate == 0 || crate == 1) fill(groupName + crate_map.at(0), eventMonitor, y_2D );
356 else if (crate == 2 || crate == 3) fill(groupName + crate_map.at(1), eventMonitor, y_2D );
357 else if (crate == 4 || crate == 5) fill(groupName + crate_map.at(2), eventMonitor, y_2D );
358 else if (crate == 6 || crate == 7) fill(groupName + crate_map.at(3), eventMonitor, y_2D );
359 moduleError.at(crate) |= (1 << module);
360 }
361 }
362 }
363
364
365
366 } // End loop over tower objects
367
368
369 // Save error vector for global summary
370 {
371 auto save = std::make_unique<ErrorVector>(crateError);
372 auto* result = SG::makeHandle(m_errorLocation, ctx).put(std::move(save));
373 if (!result) {
374 ATH_MSG_ERROR("Error recording PPMSimBS mismatch vector in TES");
375 return StatusCode::FAILURE;
376 }
377 }
378
379
380 return StatusCode::SUCCESS;
381}
382
383
385 std::vector<MonitorTT> &vecMonTT) const
386{
387 // Geometry
388 const double phi = tt->phi();
389 double phiMod = phi * m_phiScaleTT;
390
391 // LUT JEP
392 int jepET = 0;
393 const std::vector<uint_least8_t> jepETvec = tt->lut_jep();
394 if (jepETvec.size() > 0) jepET = tt->jepET();
395
396
397 // Fill TT quantities
398 MonitorTT monTT;
399 monTT.tower = tt;
400 monTT.phiScaled = phiMod;
401 monTT.jepET = jepET;
402 monTT.phi1d = 0;
403 monTT.maxADC = 0;
404 vecMonTT.push_back(monTT);
405
406 return StatusCode::SUCCESS;
407}
408
409
410StatusCode PPMSimBSMonitorAlgorithm::fillPPMEtaPhi( MonitorTT &monTT,
411 const std::string& groupName,
412 const std::string& weightName,
413 double weight) const {
414
415 // Number of bins filled in phi depends on eta due to electronics coverage
416
417 // KW to do: fill in shrinkEtaBins part
418 double phiMod = monTT.phiScaled; // Integer binning for 2D plots
419 double etaMod = monTT.tower->eta();
420 const double absEta = std::abs(etaMod);
421
422 const std::vector<double> offset32 = {1.5, 0.5, -0.5, -1.5};
423 const std::vector<double> offset25 = {0.5, -0.5};
424 std::vector<double> offset = {};
425
426 if (absEta > 3.2) {
427 // Fill four bins in phi
428 phiMod = std::floor(phiMod/4)*4. + 2.;
429 offset = std::move(offset32);
430 }
431 else if (absEta > 2.5) {
432 // Fill two bins in phi
433 phiMod = std::floor(phiMod/2)*2. + 1.;
434 offset = std::move(offset25);
435 }
436 else {
437 offset = {0.};
438 }
439
440 // Fill the histograms
441 for (auto phiOffset : offset) {
442
443 auto etaTT_2D = Monitored::Scalar<double>("etaTT_2D", etaMod);
444 auto phiTT_2D = Monitored::Scalar<double>("phiTT_2D", phiMod + phiOffset);
445
446 auto weight_2D = Monitored::Scalar<double>(weightName, weight); // Weight for filling 2D profile histograms; name must be included in python histogram definition
447
448 fill(groupName, etaTT_2D, phiTT_2D, weight_2D);
449
450 }
451
452 return StatusCode::SUCCESS;
453}
454
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_DEBUG(x)
#define y
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.
Encapsulates the ID of one channel of conditions data in COOL, ie the ID of a row in a table.
unsigned int id() const
unsigned int module(bool logical=true) const
Convert a typeId to a L1CaloModuleType.
unsigned int crate() const
Declare a monitored scalar variable.
SG::ReadCondHandleKey< L1CaloRunParametersContainer > m_runParametersContainer
StatusCode makePPMTower(const xAOD::TriggerTower *tt, std::vector< MonitorTT > &vecMonTT) const
Helper functions.
Gaudi::Property< int > m_simulationADCCut
SG::WriteHandleKey< std::vector< int > > m_errorLocation
ToolHandle< LVL1::IL1TriggerTowerToolRun3 > m_ttTool
PPMSimBSMonitorAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
StatusCode fillPPMEtaPhi(MonitorTT &monTT, const std::string &groupName, const std::string &weightName, double weight) const
virtual StatusCode fillHistograms(const EventContext &ctx) const override
adds event to the monitoring histograms
virtual StatusCode initialize() override
initialize
Gaudi::Property< double > m_phiScaleTT
Properties.
SG::ReadHandleKey< xAOD::TriggerTowerContainer > m_xAODTriggerTowerContainerName
container keys including steering parameter and description
virtual bool isValid() override final
Can the handle be successfully dereferenced?
int lb
Definition globals.cxx:23
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
TriggerTower_v2 TriggerTower
Define the latest version of the TriggerTower class.
void fill(H5::Group &out_file, size_t iterations)