ATLAS Offline Software
MistimedStreamMonitorAlgorithm.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 
8 #include <iostream>
9 #include <vector>
10 #include <TMath.h>
11 
12 MistimedStreamMonitorAlgorithm::MistimedStreamMonitorAlgorithm( const std::string& name, ISvcLocator* pSvcLocator )
13  : AthMonitorAlgorithm(name,pSvcLocator)
14 {
15 }
16 
18 
19  ATH_MSG_DEBUG("MistimedStreamMonitorAlgorith::initialize");
20  ATH_MSG_DEBUG("Package Name "<< m_packageName);
21  ATH_MSG_DEBUG("m_xAODTriggerTowerContainerName "<< m_xAODTriggerTowerContainerName);
22 
23  ATH_MSG_INFO("m_eFexEMContainer: "<< m_eFexEMContainerKey);
24  ATH_MSG_INFO("m_eFexEMOutContainer: "<< m_eFexEMOutContainerKey);
25  ATH_MSG_INFO("m_eFexTauContainer: "<< m_eFexTauContainerKey);
26 
27  // we initialise all the containers that we need
30  ATH_CHECK( m_cpmTowerLocation.initialize());
31  ATH_CHECK( m_jetElementLocation.initialize());
32  ATH_CHECK( m_trigDec.retrieve() );
33  ATH_CHECK( m_ttTool.retrieve());
37 
38  // eFex Container
39  ATH_CHECK( m_eFexEMContainerKey.initialize() );
40  ATH_CHECK( m_eFexEMOutContainerKey.initialize() );
41  ATH_CHECK( m_eFexTauContainerKey.initialize() );
42 
43  // jFex Container
44  ATH_CHECK( m_jFexLRJetContainerKey.initialize() );
45  ATH_CHECK( m_jFexSRJetContainerKey.initialize() );
46  ATH_CHECK( m_jFexTauContainerKey.initialize() );
47  ATH_CHECK( m_jFexDataTowerKey.initialize() );
48  ATH_CHECK( m_EmulTowerKey.initialize() );
49 
50  // gFex Container
51  ATH_CHECK( m_gFexJetTobKeyList.initialize() ) ;
52 
54 }
55 
57 
58  ATH_MSG_DEBUG("MistimedStreamMonitorAlgorith::fillHistograms");
59 
60  // Retrieve L1CaloRunParametersContainer
62  ATH_CHECK(runParameters.isValid());
63 
64  unsigned int readoutConfigID = runParameters->runParameters(1)->readoutConfigID();
65  ATH_MSG_DEBUG("RunParameters:: readoutConfigID " << readoutConfigID);
66 
68 
69  unsigned int channelID = 0;
70  unsigned int numFadcSlices = 0;
71  unsigned int l1aFadcSlice = 0;
72  unsigned int readout80ModePpm = 0;
73 
74  //the readout config ID tells you, which readoutConfig is loaded. now you can retrieve the l1aFadcSlice from this DB entry
75  if ( readoutConfigJSON->readoutConfigJSON(readoutConfigID)->channelId() == readoutConfigID){
76  ATH_MSG_DEBUG("readoutConfigID " << readoutConfigID);
77  channelID = readoutConfigJSON->readoutConfigJSON(readoutConfigID)->channelId();
78  numFadcSlices = readoutConfigJSON->readoutConfigJSON(readoutConfigID)->numFadcSlices();
79  l1aFadcSlice = readoutConfigJSON->readoutConfigJSON(readoutConfigID)->l1aFadcSlice();
80  readout80ModePpm = readoutConfigJSON->readoutConfigJSON(readoutConfigID)->readout80ModePpm();
81  ATH_MSG_DEBUG("channelID :: " << channelID);
82  ATH_MSG_DEBUG("numFadcSlices :: " << numFadcSlices);
83  ATH_MSG_DEBUG("l1aFadcSlice :: " << l1aFadcSlice);
84  ATH_MSG_DEBUG("readout80ModePpm :: " << readout80ModePpm);
85  }
86 
87  // Retrieve jetElementfrom SG
89  if(!jetElementTES.isValid()){
90  ATH_MSG_ERROR("No JetElement container found in TES "<< m_jetElementLocation);
91  return StatusCode::FAILURE;
92  }
93 
94  // Retrieve Core CPM Towers from SG
96  if(!cpmTowerTES.isValid()){
97  ATH_MSG_ERROR("No CPMTower container found in TES "<< m_cpmTowerLocation);
98  return StatusCode::FAILURE;
99  }
100 
101  // Retrieve Trigger Towers from SG
103  if(!triggerTowerTES.isValid()){
104  ATH_MSG_ERROR("No Trigger Tower container found in TES "<< m_xAODTriggerTowerContainerName);
105  return StatusCode::FAILURE;
106  }
107 
108  // Retrieve EventInfo from SG and save lumi block number, global event number and run number
109  unsigned int lumiNo = GetEventInfo(ctx)->lumiBlock();
110  unsigned int currentRunNo = ctx.eventID().run_number();
111  unsigned int currentEventNo = ctx.eventID().event_number();
112 
113  ATH_MSG_DEBUG("Lumi Block :: " << lumiNo);
114  ATH_MSG_DEBUG("Run Number :: " << currentRunNo);
115  ATH_MSG_DEBUG("Event Number :: " << currentEventNo);
116 
117  Monitored::Scalar<int> cutFlowX = Monitored::Scalar<int>("cutFlowX", 0);
118 
119  // fill first bin in cutflow
120  cutFlowX=All;
121  fill(m_packageName,cutFlowX);
122 
123  //for the algorithm to run, we need the 2 adc slices before and after the l1a-slice
124  //readout compatibility checks of the algo here
125  if(readout80ModePpm){
126  if(numFadcSlices < 9){
127  ATH_MSG_DEBUG("Number of ADC slices < 9 for 80 MHz readout, algorithm cannot run, aborting...");
128  return StatusCode::SUCCESS;
129  }
130  if(l1aFadcSlice < 4){
131  ATH_MSG_DEBUG("L1a readout pointer < 4 for 80 MHz readout, algorithm cannot run, aborting...");
132  return StatusCode::SUCCESS;
133  }
134  if(numFadcSlices - l1aFadcSlice < 4){
135  ATH_MSG_DEBUG("L1a readout pointer is at "<< l1aFadcSlice << " with "<< numFadcSlices << "slices at 80 MHz readout mode, algorithm cannot run, aborting...");
136  return StatusCode::SUCCESS;
137  }
138  }
139  else {
140  if(numFadcSlices < 5){
141  ATH_MSG_DEBUG("Number of ADC slices < 5 for 40 MHz readout, algorithm cannot run, aborting...");
142  return StatusCode::SUCCESS;
143  }
144  if(l1aFadcSlice < 2){
145  ATH_MSG_DEBUG("L1a readout pointer < 2 for 40 MHz readout, algorithm cannot run, aborting...");
146  return StatusCode::SUCCESS;
147  }
148  if(numFadcSlices - l1aFadcSlice < 2){
149  ATH_MSG_DEBUG("L1a readout pointer is at "<< l1aFadcSlice << " with "<< numFadcSlices << "slices at 40 MHz readout mode, algorithm cannot run, aborting...");
150  return StatusCode::SUCCESS;
151  }
152  }
153  cutFlowX=UnsuitableReadout;
154  fill(m_packageName,cutFlowX);
155 
156  //Select events that fired HLT_mistimedmonj400
157  if(! (m_trigDec->isPassed("HLT_mistimemonj400_L1All",TrigDefs::requireDecision))){
158  ATH_MSG_DEBUG("TrigDec don't pass HLT_mistimemonj400_L1All");
159  return StatusCode::SUCCESS;
160  }
161 
162  bool legacyHLT=false, phase1HLT=false;
163  const CTP_RDO* ctpBc = 0;
164  ctpBc = SG::get(m_ctpRdoReadKey);
166  ctp.setRDO(ctpBc);
167  uint32_t numberBC = ctpBc->getNumberOfBunches();
168  if (numberBC > 0) {
169  unsigned int bcPos = ctpBc->getL1AcceptBunchPosition();
170  if (currentRunNo < 472553){
171  legacyHLT = ((ctp.getBunchCrossing(bcPos-1).getTBP().test(180)) or (ctp.getBunchCrossing(bcPos+1).getTBP().test(180)));
172  phase1HLT = ((ctp.getBunchCrossing(bcPos-1).getTBP().test(224)) or (ctp.getBunchCrossing(bcPos+1).getTBP().test(224)));
173  }
174  else if (currentRunNo < 476718){
175  legacyHLT = ((ctp.getBunchCrossing(bcPos-1).getTBP().test(184)) or (ctp.getBunchCrossing(bcPos+1).getTBP().test(184)));
176  phase1HLT = ((ctp.getBunchCrossing(bcPos-1).getTBP().test(228)) or (ctp.getBunchCrossing(bcPos+1).getTBP().test(228)));
177  }
178  else {
179  legacyHLT = ((ctp.getBunchCrossing(bcPos-1).getTBP().test(185)) or (ctp.getBunchCrossing(bcPos+1).getTBP().test(185)));
180  phase1HLT = ((ctp.getBunchCrossing(bcPos-1).getTBP().test(229)) or (ctp.getBunchCrossing(bcPos+1).getTBP().test(229)));
181  }
182  }
183 
184  if ((m_uselegacy) and (legacyHLT==false)) {
185  ATH_MSG_DEBUG("TrigDec don't pass HLT_mistimemonj400_L1All");
186  return StatusCode::SUCCESS;
187  }
188  else if ((m_usephaseI) and (phase1HLT==false)) {
189  ATH_MSG_DEBUG("TrigDec don't pass HLT_mistimemonj400_L1All");
190  return StatusCode::SUCCESS;
191  }
192  // if all events fail here, check the ctp item number with the right SMUK key
193 
194  cutFlowX=HLT_mistimemonj400;
195  fill(m_packageName,cutFlowX);
196 
197  //Only select events which passed the L1_J100, L1_jJ160, L1_eEM26M, L1_jJ400 or L1_gJ400p0ETA25
198  //Adjustable depending on which trigger we are interested
199  if (m_usephaseI) {
200  if(! ( (m_trigDec->isPassed("L1_eEM26M")) or
201  (m_trigDec->isPassed("L1_gJ100p0ETA25")) or
202  (m_trigDec->isPassed("L1_gJ400p0ETA25")) or
203  (m_trigDec->isPassed("L1_jJ160")) or
204  (m_trigDec->isPassed("L1_jJ400"))
205  ) ){
206  ATH_MSG_DEBUG("TrigDec doesn't pass");
207  return StatusCode::SUCCESS;
208  }
209  }
210 
211  else if (m_uselegacy) {
212  if(! (m_trigDec->isPassed("L1_J100")) ){
213  ATH_MSG_DEBUG("TrigDec doesn't pass");
214  return StatusCode::SUCCESS;
215  }
216  }
217 
218  else {
219  ATH_MSG_ERROR("No trigger selected...aborting");
220  return StatusCode::FAILURE;
221  }
222 
223  //Define trigger for subsequent cuts
224  bool legacyTrigger= false;
225  bool phase1Trigger= false;
226  std::string trigger = "";
227 
228  if ((m_uselegacy) and (m_trigDec->isPassed("L1_J100")) ) {
229  legacyTrigger= true;
230  }
231  else if (m_usephaseI) {
232  if (m_trigDec->isPassed("L1_eEM26M")) {
233  phase1Trigger= true;
234  trigger = "eFex";
235  }
236  if ((m_trigDec->isPassed("L1_jJ160"))or (m_trigDec->isPassed("L1_jJ400"))) {
237  phase1Trigger= true;
238  trigger = "jFex";
239  }
240  if ( (m_trigDec->isPassed("L1_gJ400p0ETA25")) or (m_trigDec->isPassed("L1_gJ100p0ETA25")) ) {
241  phase1Trigger= true;
242  trigger = "gFex";
243  }
244  }
245 
246  cutFlowX=L1_Trigger;
247  fill(m_packageName,cutFlowX);
248 
249 
250  // now classify the tower signals by looking at their FADC counts, if it exceeds 70
251  int badCounter = 0; // category 2 really bad
252  int bad2Counter = 0; // category 4 bad peak 2
253  int bad3Counter = 0; // category 6 bad peak 3
254  int good3Counter = 0; // category 5 good peak 3
255  int good2Counter = 0; // category 5 good peak 3
256  int eFexintimeCounter = 0; // in-time TOBs
257  int eFexoutoftimeCounter = 0; // out-of-time TOBs
258  int jFexCounter = 0; // in-time TOBs
259  int gFexCounter = 0; // in-time TOBs
260  int emActivityCounter = 0; //count number of TT in EM layer with ADC > 70
261 
262  double dEta = 0., dPhi = 0., dPhi1 = 0., dR = 0.;
263  double etaIn = 0., phiIn = 0., etIn = 0.;
264  double etaOut = 0., phiOut = 0., etOut = 0.;
265  bool overlap = false;
266 
268  if(!jFexSRJetContainer.isValid()) {
269  ATH_MSG_WARNING("No jFex SR Jet container found in storegate "<< m_jFexSRJetContainerKey<<". Will be skipped!");
270  }
271 
272  // =====================================================================
273  // ================= Container: TriggerTower ===========================
274  // =====================================================================
275 
276  // Creating a new container for saving pulseClassification
277  std::unique_ptr<xAOD::TriggerTowerContainer> ttContainer = std::make_unique<xAOD::TriggerTowerContainer>();
278  std::unique_ptr<xAOD::TriggerTowerAuxContainer> ttContainerAux = std::make_unique<xAOD::TriggerTowerAuxContainer>();
279  ttContainer->setStore(ttContainerAux.get());
280 
281  static const SG::Accessor<float> pulseClassificationAcc("pulseClassification");
282 
283  // Creating a new container for TT with pulseClassification
284  for (const xAOD::TriggerTower* tt : *triggerTowerTES) {
285 
286  float ttPulseCategory = 0;
287  const std::vector<uint16_t>& ttADC = (tt)->adc();
288  std::vector<uint16_t> readoutCorrectedADC; //this is the standard readout ADC vector: 5 40MHz samples with l1A in the middle
289  if(!readout80ModePpm){//40 MHz
290  //just acess the acd vector, as the sanity checks where done above
291  readoutCorrectedADC.push_back(ttADC.at(l1aFadcSlice-2));
292  readoutCorrectedADC.push_back(ttADC.at(l1aFadcSlice-1));
293  readoutCorrectedADC.push_back(ttADC.at(l1aFadcSlice));
294  readoutCorrectedADC.push_back(ttADC.at(l1aFadcSlice+1));
295  readoutCorrectedADC.push_back(ttADC.at(l1aFadcSlice+2));
296  }
297  else{//80 MHz
298  readoutCorrectedADC.push_back(ttADC.at(l1aFadcSlice-4));
299  readoutCorrectedADC.push_back(ttADC.at(l1aFadcSlice-2));
300  readoutCorrectedADC.push_back(ttADC.at(l1aFadcSlice));
301  readoutCorrectedADC.push_back(ttADC.at(l1aFadcSlice+2));
302  readoutCorrectedADC.push_back(ttADC.at(l1aFadcSlice+4));
303  }
304 
305  // retrieve max ADC value and position, this seems to be buggy in the DAOD
306  auto maxValIterator = std::max_element(readoutCorrectedADC.begin(), readoutCorrectedADC.end());
307  int maxADCval = *maxValIterator;
308  int adcPeakPositon = std::distance(std::begin(readoutCorrectedADC), maxValIterator);
309 
310  if(maxADCval < 70){
311  ttPulseCategory = 0.1;
312  }
313  else if(maxADCval == 1023) {
314  ttPulseCategory = 1;
315  if(! (tt)->layer()) emActivityCounter++;
316  }
317  else{
318  bool goodQual = pulseQuality(readoutCorrectedADC, adcPeakPositon);
319  if(! (tt)->layer()) emActivityCounter++;
320  //look at any of the five FADC values
321  if(adcPeakPositon == 2){ // can be class 3 or 4 now
322  if(goodQual){
323  //nicely peaking TT in BCID0
324  good2Counter++;
325  ttPulseCategory = 3;
326  }
327  else{
328  //badly peaking TT in BCID0
329  bad2Counter++;
330  ttPulseCategory = 4;
331  }
332  }
333  else if(adcPeakPositon == 3){ // can be class 5 or 6 now
334  if(goodQual){
335  //nicely peaking TT in BCID+1
336  good3Counter++;
337  ttPulseCategory = 5;
338  }
339  else{
340  //badly peaking TT in BCID+1
341  bad3Counter++;
342  ttPulseCategory = 6;
343  }
344  }
345  else{
346  //TT peaking in BCID-1,-2 or +2
347  badCounter++;
348  ttPulseCategory = 2;
349  }
350 
351  if (trigger == "jFex") {
353  CHECK( evtStore()->retrieve( jFexSRJetRoI, "L1_jFexSRJetRoI" ) );
354  for(auto tob : *jFexSRJetRoI) {
355  etaIn = tob->eta();
356  phiIn = tob->phi();
357  etIn = tob->tobEt()/5;
358 
359  if( (adcPeakPositon == 3) and (goodQual) ) {
360  etaOut = tt->eta();
361  phiOut = tt->phi()-M_PI;
362  dEta = std::abs(etaIn-etaOut);
363  dPhi = std::abs(phiIn-phiOut);
364  if ((phiIn < 0) and (phiOut > 0)){
365  dPhi1 = std::abs((phiIn+2*M_PI)-phiOut);
366  if (dPhi1 < dPhi) {
367  dPhi = dPhi1;
368  }
369  }
370  else if ((phiIn > 0) and (phiOut < 0)){
371  dPhi1 = std::abs(phiIn-(phiOut+2*M_PI));
372  if (dPhi1 < dPhi) {
373  dPhi = dPhi1;
374  }
375  }
376  dR = TMath::Sqrt(dEta*dEta+dPhi*dPhi);
377  if ((dR < .2) and (etIn > 160.)) {
378  overlap = true;
379  }
380  } // if statement - good tt
381  } // for loop - jFex TOBs
382  } // if statement - jFex
383 
384  if (trigger == "gFex") {
385 
386  for (const auto& key : m_gFexJetTobKeyList){
388  // Check that this container is present
389  if ( !jetContainer.isValid() ) {
390  ATH_MSG_WARNING("No gFex jet container found in storegate: "<< key.key());
391  }
392  else {
394  CHECK( evtStore()->retrieve( gFexJetRoI, key.key() ) );
395  for(auto tob : *gFexJetRoI) {
396  etaIn = tob->eta();
397  phiIn = tob->phi();
398  etIn = tob->gFexTobEt()/10;
399 
400  if( (adcPeakPositon == 3) and (goodQual) ) {
401  etaOut = tt->eta();
402  phiOut = tt->phi()-M_PI;
403  dEta = std::abs(etaIn-etaOut);
404  dPhi = std::abs(phiIn-phiOut);
405  if ((phiIn < 0) and (phiOut > 0)){
406  dPhi1 = std::abs((phiIn+2*M_PI)-phiOut);
407  if (dPhi1 < dPhi) {
408  dPhi = dPhi1;
409  }
410  }
411  else if ((phiIn > 0) and (phiOut < 0)){
412  dPhi1 = std::abs(phiIn-(phiOut+2*M_PI));
413  if (dPhi1 < dPhi) {
414  dPhi = dPhi1;
415  }
416  }
417  dR = TMath::Sqrt(dEta*dEta+dPhi*dPhi);
418  if ((dR < .2) and (etIn > 100.)) {
419  overlap = true;
420  }
421  } // if statement - good tt
422  } // for loop - gFex TOBs
423  } // else stamement - valid container
424  } // for loop - gFex container
425  } // if statement - gFex
426 
427  }
428 
429  // decorate the TT in order to have to recompute the pulse categorisation
430  xAOD::TriggerTower* newTT = new xAOD::TriggerTower; //create a new TT object
431  ttContainer->push_back(newTT); // add the newTT to new output TT container (at the end of it)
432  *newTT = *(tt);// copy over all information from TT to newTT
433  pulseClassificationAcc(*newTT) = ttPulseCategory; //decorate
434  }
435 
436  // count all eFex in-time and out-of-time TOBs with at least 5GeV
437  for(auto key : {"L1_eEMxRoI","L1_eEMxRoIOutOfTime"}) {
438 
439  const xAOD::eFexEMRoIContainer* emTobs;
440  CHECK( evtStore()->retrieve( emTobs, key ) );
441 
442  for(auto tob : *emTobs) {
443  if (tob->et() > 5000) { //eFex TOB energy in MeV
444  if (tob->bcn4() == ((ctx.eventID().bunch_crossing_id()) & 0xf )) {
445  eFexintimeCounter++;
446  }
447  else if (tob->bcn4() == (((ctx.eventID().bunch_crossing_id())+1) & 0xf )) {
448  eFexoutoftimeCounter++;
449  }
450  }
451  }
452 
453  }
454 
455  // count all gFex in-time TOBs with at least 5GeV
456  const xAOD::gFexJetRoIContainer* gFexLRJetRoI;
457  CHECK( evtStore()->retrieve( gFexLRJetRoI, "L1_gFexLRJetRoI" ) );
458  for(auto tob : *gFexLRJetRoI) {
459  if (tob->et() > 50) { //gFex TOB energy in 0.1GeV
460  gFexCounter++;
461  }
462  }
463 
464  // count all jFex in-time TOBs with at least 5GeV
465  const xAOD::jFexSRJetRoIContainer* jFexJetRoI;
466  CHECK( evtStore()->retrieve( jFexJetRoI, "L1_jFexSRJetRoI" ) );
467  for(auto tob : *jFexJetRoI) {
468  if (tob->et() > 25) { //jFex TOB energy in 0.2GeV
469  jFexCounter++;
470  }
471  }
472 
473  if(badCounter > 4){
474  //reject events with more than 4 wrongly peaked towers
475  return StatusCode::SUCCESS;
476  }
477  cutFlowX=badpeakTT;
478  fill(m_packageName,cutFlowX);
479 
480  if(bad2Counter > 4){
481  //reject events with more than 4 pulses peaking in slice 2 that are badly timed or mis-shapen
482  return StatusCode::SUCCESS;
483  }
484  cutFlowX=badCentralTT;
485  fill(m_packageName,cutFlowX);
486 
487  if(bad3Counter > 4){
488  //reject events with more than 4 pulses peaking in slice 3 that are badly timed or mis-shapen
489  return StatusCode::SUCCESS;
490  }
491  cutFlowX=badLateTT;
492  fill(m_packageName,cutFlowX);
493 
494  if( (good3Counter < 2) or ((trigger == "eFex") and (eFexoutoftimeCounter < 2)) ){
495  //reject events with less than 2 pulses nicely peaking in slice 3
496  return StatusCode::SUCCESS;
497  }
498  cutFlowX=lateTT;
499  fill(m_packageName,cutFlowX);
500 
501  if( (good2Counter > 3) or
502  ((trigger == "eFex") and (eFexintimeCounter > 3)) or
503  ((trigger == "jFex") and (jFexCounter > 3)) or
504  ((trigger == "gFex") and (gFexCounter > 3)) ){
505  //reject events with more than 3 pulses nicely peaking/ 3 TOBs in slice 2 to avoid event being triggered by pileup
506  return StatusCode::SUCCESS;
507  }
508  cutFlowX= InTime;
509  fill(m_packageName,cutFlowX);
510 
511  if(!emActivityCounter){
512  //reject events with no activity in the EM layer
513  return StatusCode::SUCCESS;
514  }
515  cutFlowX= TTEMLayer;
516  fill(m_packageName,cutFlowX);
517 
518  if (trigger == "eFex") {
519  const xAOD::eFexEMRoIContainer* emTobs;
520  CHECK( evtStore()->retrieve( emTobs, "L1_eEMxRoI" ) );
521  const xAOD::eFexEMRoIContainer* emTobsOut;
522  CHECK( evtStore()->retrieve( emTobsOut, "L1_eEMxRoIOutOfTime" ) );
523 
524  for(auto tob : *emTobs) {
525  etaIn = tob->eta();
526  phiIn = tob->phi();
527  etIn = tob->et()/1000; //eT in GeV
528 
529  for(auto tobOut : *emTobsOut) {
530  etaOut = tobOut->eta();
531  phiOut = tobOut->phi();
532  etOut = tobOut->et()/1000; //eT in GeV
533 
534  dEta = std::abs(etaIn-etaOut);
535  dPhi = std::abs(phiIn-phiOut);
536  if ((phiIn < 0) and (phiOut > 0)){
537  dPhi1 = std::abs((phiIn+2*M_PI)-phiOut);
538  if (dPhi1 < dPhi) {
539  dPhi = dPhi1;
540  }
541  }
542  else if ((phiIn > 0) and (phiOut < 0)){
543  dPhi1 = std::abs(phiIn-(phiOut+2*M_PI));
544  if (dPhi1 < dPhi) {
545  dPhi = dPhi1;
546  }
547  }
548  dR = TMath::Sqrt(dEta*dEta+dPhi*dPhi);
549  if ((dR < .2) and (etIn > 26.) and (etOut > 26.)){
550  overlap = true;
551  }
552  }
553  }
554  }
555 
556  if ((legacyTrigger) and !(phase1Trigger)){
557  overlap = true;
558  }
559 
560  if(overlap==false){
561  //reject events where BCID and BCID+1 are spatially separated
562  return StatusCode::SUCCESS;
563  }
564  cutFlowX= EtaPhiOverlap;
565  fill(m_packageName,cutFlowX);
566 
567 
568  // scope for mutable error event per lumi block tt counter
569  // it allows only one event per lumiblock
570  std::lock_guard<std::mutex> lock(m_mutex);
571  m_event_counter[lumiNo]+=1;
572  const int eventCounter = m_eventCounter++;
573 
574  if( (m_event_counter[lumiNo] <m_maxEvents) && (eventCounter < m_maxEvents) ){
575  ATH_MSG_DEBUG( "EventID :: " << m_event_counter[lumiNo]);
576 
577  // Saving the lumiblock and event number of the events with mistimed
578  auto eventMonitor_legacy= Monitored::Scalar<std::string>("eventMonitor_legacy", "Event"+std::to_string(eventCounter)+"="+std::to_string(currentEventNo));
579  auto eventMonitor_phaseI= Monitored::Scalar<std::string>("eventMonitor_phaseI", "Event"+std::to_string(eventCounter)+"_"+trigger+"="+std::to_string(currentEventNo));
580  auto lbMonitor= Monitored::Scalar<std::string>("lbMonitor", std::to_string(lumiNo));
581  std::string groupName = "Event_";
582  if (legacyTrigger) {
583  fill(groupName, eventMonitor_legacy, lbMonitor );
584  }
585  if (phase1Trigger) {
586  fill(groupName, eventMonitor_phaseI, lbMonitor );
587  }
588 
589  // Create a vector of trigger towers with quantities to be monitored
590  std::vector<MonitorTT> vecMonTTDecor; // All towers
591 
592  // Loop over trigger tower container
593  //Create the trigger tower objects and calculate scaled phi
594  for (const xAOD::TriggerTower* tt : *ttContainer) {
595  ATH_CHECK( makeTowerPPM(tt, vecMonTTDecor) );
596  ATH_MSG_DEBUG( "tt->pulseClassification :: " << pulseClassificationAcc(*tt));
597  }
598 
599  groupName = "EventofInterest_" + std::to_string(eventCounter) + "_";
600  auto bcidWord = Monitored::Scalar<uint8_t>("bcidWord", 0);
601  auto pulseCat = Monitored::Scalar<float>("pulseCat", 0);
602 
603  for (auto& myTower : vecMonTTDecor) {
604  ATH_MSG_DEBUG(" looping over TTs");
605  const int layer = (myTower.tower)->layer();
606  pulseCat = pulseClassificationAcc(*myTower.tower);
607  bcidWord = (myTower.tower)->bcidVec()[0]; // look at the status bit in the central time slice
608  ATH_MSG_DEBUG("groupName :: " << groupName);
609 
610  // Check if TT is in EM or HAD layer:
611  if (layer == 0) { //========== ELECTROMAGNETIC LAYER =========================
612  ATH_CHECK( fillPPMEtaPhi(myTower, groupName+"TT_EM", "pulseCat", pulseCat) );
613  if(pulseCat > 0.5 && bcidWord > 0) {
614  ATH_CHECK( fillPPMEtaPhi(myTower, groupName+"TT_EM", "bcidWord", bcidWord) );
615  }
616  }
617  else if(layer == 1 ) { //========== HADRONIC LAYER ===============================
618  ATH_CHECK( fillPPMEtaPhi(myTower, groupName+"TT_HAD", "pulseCat", pulseCat) );
619  if(pulseCat > 0.5 && bcidWord > 0 ) ATH_CHECK( fillPPMEtaPhi(myTower, groupName+"TT_HAD", "bcidWord", bcidWord) );
620  }
621  }
622 
623  //Loop over CPM tower container
624  //Create the CPM objects and calculate scaled phi
625  std::vector<MonitorCPM> vecMonCPM; // All towers
626  for (const xAOD::CPMTower* cpm : *cpmTowerTES) {
627  ATH_CHECK( makeTowerCPM(cpm, vecMonCPM) );
628  }
629 
630  // Coordinates for CPM tower and JetElement containers
631  auto etalut = Monitored::Scalar<double>("etalut", 0);
632  auto philut = Monitored::Scalar<double>("philut", 0);
633 
634  // lut variables
635  auto emLUT0 = Monitored::Scalar<int>("emLUT0", 0);
636  auto emLUT1 = Monitored::Scalar<int>("emLUT1", 0);
637  auto emLUT2 = Monitored::Scalar<int>("emLUT2", 0);
638  auto hadLUT0 = Monitored::Scalar<int>("hadLUT0", 0);
639  auto hadLUT1 = Monitored::Scalar<int>("hadLUT1", 0);
640  auto hadLUT2 = Monitored::Scalar<int>("hadLUT2", 0);
641 
642  //loop over the cpm tower container to fill the lut histos
643  for (auto& myTower : vecMonCPM) {
644 
645  std::vector<uint8_t> cpmEMenergy = (myTower.tower)->emEnergyVec();
646  std::vector<uint8_t> cpmHADenergy = (myTower.tower)->hadEnergyVec();
647  // eta scaled
648  etalut = myTower.etaScaled;
649 
650  for (auto phi: myTower.phiScaled) {
651  // phi scaled
652  philut = phi;
653 
654  if(cpmEMenergy.size() > 2){ // expect 3 slices to be read out
655  ATH_MSG_DEBUG("CPM :: emLUT0 :: " << static_cast<unsigned>(cpmEMenergy.at(0)) << ":: emLUT1 :: " << static_cast<unsigned>(cpmEMenergy.at(1)) << ":: emLUT2 :: " << static_cast<unsigned>(cpmEMenergy.at(2)));
656 
657  emLUT0 = static_cast<int>(cpmEMenergy.at(0));
658  if(cpmEMenergy.at(0) > 0) fill(groupName+"lut_EM0",etalut,philut, emLUT0);
659 
660  emLUT1 = static_cast<int>(cpmEMenergy.at(1));
661  if(cpmEMenergy.at(1) > 0) fill(groupName+"lut_EM1",etalut,philut, emLUT1);
662 
663  emLUT2 = static_cast<int>(cpmEMenergy.at(2));
664  if(cpmEMenergy.at(2) > 0) fill(groupName+"lut_EM2",etalut,philut, emLUT2);
665  }
666  if(cpmHADenergy.size() > 2){
667  ATH_MSG_DEBUG("CPM :: hadLUT0 :: " << static_cast<unsigned>(cpmHADenergy.at(0)) << ":: hadLUT1 :: " << static_cast<unsigned>(cpmHADenergy.at(1)) << ":: hadLUT2 :: " << static_cast<unsigned>(cpmHADenergy.at(2)));
668 
669  hadLUT0 = static_cast<int>(cpmHADenergy.at(0));
670  if(cpmHADenergy.at(0) > 0) fill(groupName+"lut_HAD0",etalut,philut, hadLUT0);
671  hadLUT1 = static_cast<int>(cpmHADenergy.at(1));
672  if(cpmHADenergy.at(1) > 0) fill(groupName+"lut_HAD1",etalut,philut, hadLUT1);
673  hadLUT2 = static_cast<int>(cpmHADenergy.at(2));
674  if(cpmHADenergy.at(2) > 0)fill(groupName+"lut_HAD2",etalut,philut, hadLUT2);
675  }
676  }
677  }
678 
679  std::vector<MonitorJE> vecMonJE; // All elements
680 
681  //Create the JetElement objects and calculate scaled phi
682  for (const xAOD::JetElement* je : *jetElementTES) {
683  ATH_CHECK( makeTowerJE(je, vecMonJE) );
684  }
685 
686  //loop over the jet element container to fill the lut histos
687  for (auto& jet : vecMonJE) {
688 
689  std::vector<uint16_t> jepEMenergy = (jet.element)->emJetElementETVec();
690  std::vector<uint16_t> jepHADenergy = (jet.element)->hadJetElementETVec();
691 
692  for (auto eta: jet.etaScaled) {
693  etalut = eta;
694  if ( std::abs(eta) > 2.5){
695  for (auto phi: jet.phiScaled) {
696  philut = phi;
697  if(jepEMenergy.size() > 2){
698  ATH_MSG_DEBUG("JetElement :: emLUT0 :: " << static_cast<unsigned>(jepEMenergy.at(0)) << ":: emLUT1 :: " << static_cast<unsigned>(jepEMenergy.at(1)) << ":: emLUT2 :: " << static_cast<unsigned>(jepEMenergy.at(2)));
699 
700  emLUT0 = static_cast<int>(jepEMenergy.at(0));
701  if(jepEMenergy.at(0) > 0) fill(groupName+"lut_EM0",etalut,philut, emLUT0);
702 
703  emLUT1 = static_cast<int>(jepEMenergy.at(1));
704  if(jepEMenergy.at(1) > 0) fill(groupName+"lut_EM1",etalut,philut, emLUT1);
705 
706  emLUT2 = static_cast<int>(jepEMenergy.at(2));
707  if(jepEMenergy.at(2) > 0) fill(groupName+"lut_EM2",etalut,philut, emLUT2);
708  }
709  if(jepHADenergy.size()> 2){
710  ATH_MSG_DEBUG("JetElement :: hadLUT0 :: " << static_cast<unsigned>(jepHADenergy.at(0)) << ":: hadLUT1 :: " << static_cast<unsigned>(jepHADenergy.at(1)) << ":: hadLUT2 :: " << static_cast<unsigned>(jepHADenergy.at(2)));
711 
712  hadLUT0 = static_cast<int>(jepHADenergy.at(0));
713  if(jepHADenergy.at(0) > 0) fill(groupName+"lut_HAD0",etalut,philut, hadLUT0);
714 
715  hadLUT1 = static_cast<int>(jepHADenergy.at(1));
716  if(jepHADenergy.at(1) > 0) fill(groupName+"lut_HAD1",etalut,philut, hadLUT1);
717 
718  hadLUT2 = static_cast<int>(jepHADenergy.at(2));
719  if(jepHADenergy.at(2) > 0) fill(groupName+"lut_HAD2",etalut,philut, hadLUT2);
720  }
721  }
722  }
723  }
724  }
725 
727  if ( !eFexContainer.isValid() ) {
728  ATH_MSG_WARNING("No eFex EM container found in storegate "<< eFexContainer.key());
729  }
730 
731  // monitored variables for histograms
732  auto TOBeT = Monitored::Scalar<float>("TOBTransverseEnergy",0.0);
733  auto TOBeta = Monitored::Scalar<float>("TOBEta",0.0);
734  auto TOBphi = Monitored::Scalar<float>("TOBPhi",0.0);
735  auto TOBeT_max = Monitored::Scalar<float>("TOBTransverseEnergy_max",0.0);
736  auto TOBeta_max = Monitored::Scalar<float>("TOBEta_max",0.0);
737  auto TOBphi_max = Monitored::Scalar<float>("TOBPhi_max",0.0);
738  auto TOBeT_max_in = Monitored::Scalar<float>("TOBTransverseEnergy_max",0.0);
739  auto TOBeta_max_in = Monitored::Scalar<float>("TOBEta_max",0.0);
740  auto TOBphi_max_in = Monitored::Scalar<float>("TOBPhi_max",0.0);
741 
742  TOBeT_max = 0;
743  TOBeT_max_in = 0;
744 
745  for(auto key : {"L1_eEMxRoI","L1_eEMxRoIOutOfTime"}) {
746 
747  const xAOD::eFexEMRoIContainer* emTobs;
748  CHECK( evtStore()->retrieve( emTobs, key ) );
749 
750  for(auto tob : *emTobs) {
751  TOBeT = tob->et()/1000; //eT in GeV
752  TOBeta = tob->eta();
753 
754  // adjust the phi to 0 to 2 pi
755  if (tob->phi() < 0) {
756  TOBphi = tob->phi()+2*M_PI;
757  }
758  else {
759  TOBphi = tob->phi();
760  }
761 
762  // fill the eFex histograms in the right time slice
763  if (tob->bcn4() == (((ctx.eventID().bunch_crossing_id())-1) & 0xf )) {
764  if (TOBeT > 0.0){
765  fill(groupName+"Efex0", TOBeta, TOBphi, TOBeT);
766  }
767  }
768  else if (tob->bcn4() == ((ctx.eventID().bunch_crossing_id()) & 0xf )) {
769  if (TOBeT > 0.0){
770  if (TOBeT_max_in < TOBeT) {
771  TOBeT_max_in = tob->et()/1000;
772  TOBeta_max_in = tob->eta();
773  if (tob->phi() < 0) {
774  TOBphi_max_in = tob->phi()+2*M_PI;
775  }
776  else {
777  TOBphi_max_in = tob->phi();
778  }
779  }
780  fill(groupName+"Efex1", TOBeta, TOBphi, TOBeT);
781  if (trigger == "eFex") {
782  fill("Efex_maxTOB_in", TOBeT);
783  }
784  }
785  }
786  else if (tob->bcn4() == (((ctx.eventID().bunch_crossing_id())+1) & 0xf )) {
787  if (TOBeT > 0.0){
788  if (TOBeT_max < TOBeT) {
789  TOBeT_max = tob->et()/1000;
790  TOBeta_max = tob->eta();
791  if (tob->phi() < 0) {
792  TOBphi_max = tob->phi()+2*M_PI;
793  }
794  else {
795  TOBphi_max = tob->phi();
796  }
797  }
798  fill(groupName+"Efex2", TOBeta, TOBphi, TOBeT);
799  if (trigger == "eFex") {
800  fill("Efex_maxTOB_out", TOBeT);
801  }
802  }
803  }
804  }
805  }
806  if (trigger == "eFex") {
807  fill("Efex_maxTOB_out", TOBeta_max, TOBphi_max);
808  fill("Efex_maxTOB_in", TOBeta_max_in, TOBphi_max_in);
809  }
810 
811  // variables for histograms
812  auto jFexEt = Monitored::Scalar<int> ("jFexEt",0);
813  auto jFexeta = Monitored::Scalar<float>("jFexEta",0.0);
814  auto jFexphi = Monitored::Scalar<float>("jFexPhi",0.0);
815 
816  // Access jFex tower container
818  if(!jFexTowerContainer.isValid()) {
819  ATH_MSG_WARNING("No jFex Tower container valid in storegate with key: "<< m_jFexDataTowerKey<<". Will be skipped!");
820  }
821 
822  //SG::ReadHandle<xAOD::jFexTowerContainer> jFexEmulatedTowerContainer{m_jFexEmulatedTowerKey, ctx};
823  SG::ReadHandle<xAOD::jFexTowerContainer> jEmulatedTowerContainer;
824  jEmulatedTowerContainer = SG::ReadHandle<xAOD::jFexTowerContainer>(m_EmulTowerKey,ctx);
825  if(!jEmulatedTowerContainer.isValid()) {
826  ATH_MSG_WARNING("No jFex Tower container valid in storegate with key: "<< jEmulatedTowerContainer.key()<<". Will be skipped!");
827  }
828  else {
829  for(const xAOD::jFexTower* emulTower : *jEmulatedTowerContainer) {
830  jFexEt=emulTower->et_count().at(0);
831  //Adding 1e-5 for plotting style
832  jFexeta=emulTower->eta()+1e-5;
833  if (emulTower->phi() < 0) {
834  jFexphi=emulTower->phi()+2*M_PI;
835  }
836  else {
837  jFexphi=emulTower->phi();
838  }
839  if (jFexEt > 175) {
840  fill(groupName+"JfexEmulated",jFexeta,jFexphi, jFexEt);
841  }
842  }
843  }
844 
845  TOBeT_max = 0;
846  for(const xAOD::jFexSRJetRoI* jFexSRJetRoI : *jFexSRJetContainer) {
847  if(jFexSRJetRoI->tobWord()==0) continue; //remove empty TOBs
848  jFexEt=jFexSRJetRoI->tobEt()/5;
849  jFexeta=jFexSRJetRoI->eta();
850  if (jFexSRJetRoI->phi() < 0) {
851  jFexphi=jFexSRJetRoI->phi()+2*M_PI;
852  }
853  else {
854  jFexphi=jFexSRJetRoI->phi();
855  }
856  if (TOBeT_max < jFexEt) {
857  TOBeT_max = jFexSRJetRoI->tobEt()/5;
858  TOBeta_max = jFexSRJetRoI->eta();
859  if (jFexSRJetRoI->phi() < 0) {
860  TOBphi_max =jFexSRJetRoI->phi()+2*M_PI;
861  }
862  else {
863  TOBphi_max =jFexSRJetRoI->phi();
864  }
865  }
866  fill(groupName+"JfexSRJet", jFexeta, jFexphi, jFexEt);
867  if (trigger == "jFex") {
868  fill("Jfex_maxTOB", jFexEt);
869  }
870  }
871  if (trigger == "jFex") {
872  fill("Jfex_maxTOB", TOBeta_max, TOBphi_max);
873  }
874 
876  if(!jFexTauContainer.isValid()) {
877  ATH_MSG_WARNING("No jFex Tau container found in storegate "<< m_jFexTauContainerKey<<". Will be skipped!");
878  }
879  else {
880  for(const xAOD::jFexTauRoI* jFexTauRoI : *jFexTauContainer) {
881  if(jFexTauRoI->tobWord()==0) continue; //remove empty TOBs
882  jFexEt =jFexTauRoI->tobEt()/5;
883  jFexeta=jFexTauRoI->eta();
884  if (jFexTauRoI->phi() < 0) {
885  jFexphi=jFexTauRoI->phi()+2*M_PI;
886  }
887  else {
888  jFexphi=jFexTauRoI->phi();
889  }
890  fill(groupName+"JfexTau", jFexeta, jFexphi, jFexEt);
891  }
892  }
893 
894  auto gFexEt = Monitored::Scalar<int> ("gFexEt",0);
895  auto gFexEta = Monitored::Scalar<float>("gFexEta",0.0);
896  auto gFexPhi = Monitored::Scalar<float>("gFexPhi",0.0);
897  int key_index = 0;
898 
899  TOBeT_max = 0;
900  // Small-R and large-R jets container loop
901  for (const auto& key : m_gFexJetTobKeyList){
903  // Check that this container is present
904  if ( !jetContainer.isValid() ) {
905  ATH_MSG_WARNING("No gFex jet container found in storegate: "<< key.key());
906  }
907  else {
908  for(const xAOD::gFexJetRoI* gFexJetRoIContainer : *jetContainer) {
909  gFexEt =gFexJetRoIContainer->gFexTobEt()/10;
910  gFexEta=gFexJetRoIContainer->eta();
911  if (gFexJetRoIContainer->phi() < 0) {
912  gFexPhi=gFexJetRoIContainer->phi()+2*M_PI;
913  }
914  else {
915  gFexPhi=gFexJetRoIContainer->phi();
916  }
917  if (TOBeT_max < gFexEt) {
918  TOBeT_max = gFexJetRoIContainer->gFexTobEt()/10;
919  TOBeta_max = gFexJetRoIContainer->eta();
920  if (gFexJetRoIContainer->phi() < 0) {
921  TOBphi_max=gFexJetRoIContainer->phi()+2*M_PI;
922  }
923  else {
924  TOBphi_max=gFexJetRoIContainer->phi();
925  }
926  }
927  if (key_index == 0) {
928  fill(groupName+"GfexSRJet",gFexEta, gFexPhi, gFexEt);
929  }
930  else if (key_index == 1) {
931  fill(groupName+"GfexLRJet",gFexEta, gFexPhi, gFexEt);
932  }
933  if (trigger == "gFex") {
934  fill("Gfex_maxTOB", gFexEt);
935  }
936  }
937  }
938  key_index++;
939  }
940  if (trigger == "gFex") {
941  fill("Gfex_maxTOB", TOBeta_max, TOBphi_max);
942  }
943 
944  }
945  else {
946  auto eventMonitor_all_legacy= Monitored::Scalar<std::string>("eventMonitor_all_legacy", std::to_string(currentEventNo));
947  auto eventMonitor_all_phaseI= Monitored::Scalar<std::string>("eventMonitor_all_phaseI", trigger+"="+std::to_string(currentEventNo));
948  auto lbMonitor_all= Monitored::Scalar<std::string>("lbMonitor_all", std::to_string(lumiNo));
949  if (legacyTrigger) {
950  fill("Event_all_", eventMonitor_all_legacy, lbMonitor_all );
951  }
952  if (phase1Trigger) {
953  fill("Event_all_", eventMonitor_all_phaseI, lbMonitor_all );
954  }
955  }
956 
957  return StatusCode::SUCCESS;
958 }
959 
960 
962  std::vector<MonitorTT> &vecMonTT) const
963 {
964  // Geometry
965  const double phi = tt->phi();
966  double phiMod = phi * m_phiScaleTT;
967 
968 
969 
970  // Fill TT quantities
971  MonitorTT monTT;
972  monTT.tower = tt;
973  monTT.phiScaled = phiMod;
974  monTT.phi1d = 0;
975  vecMonTT.push_back(monTT);
976 
977  return StatusCode::SUCCESS;
978 }
979 
980 
982  std::vector<MonitorCPM> &vecMonCPM) const
983 {
984  // Geometry
985  const double phi = cpm->phi();
986  double phiMod = phi * m_phiScaleTT;
987 
988 
989  // Fill CPM quantities
990  MonitorCPM monCPM;
991  monCPM.tower = cpm;
992 
993  double etaMod = monCPM.tower->eta();
994  const double absEta = std::abs(etaMod);
995 
996  const std::vector<double> offset32 = {1.5, 0.5, -0.5, -1.5};
997  const std::vector<double> offset25 = {0.5, -0.5};
998  std::vector<double> offset = {};
999 
1000  if (absEta > 3.2) {
1001  // Fill four bins in phi
1002  phiMod = std::floor(phiMod/4)*4. + 2.;
1003  offset = offset32;
1004  }
1005  else if (absEta > 2.5) {
1006  // Fill two bins in phi
1007  phiMod = std::floor(phiMod/2)*2. + 1.;
1008  offset = offset25;
1009  }
1010  else {
1011  offset = {0.};
1012  }
1013 
1014 
1015 
1016  // Fill the histograms
1017  for (auto phiOffset : offset) {
1018  monCPM.phiScaled.push_back(phiMod + phiOffset);
1019  }
1020 
1021  monCPM.etaScaled = etaMod;
1022 
1023 
1024  vecMonCPM.push_back(monCPM);
1025 
1026  return StatusCode::SUCCESS;
1027 }
1028 
1030  std::vector<MonitorJE> &vecMonJE) const
1031 {
1032 
1033  // Use JEP info to fill the forward part of the lut plots, but since this has TT granularity we have to play some tricks
1034 
1035  // Geometry
1036  const double phi = je->phi();
1037  double phiMod = phi * m_phiScaleTT;
1038 
1039  // Fill JE quantities
1040  MonitorJE monJE;
1041  monJE.element = je;
1042 
1043  double etaMod = monJE.element->eta();
1044  const double absEta = std::abs(etaMod);
1045  int signeta = 1;
1046  if( etaMod < 0) signeta = -1;
1047 
1048 
1049  const std::vector<double> offset32 = {1.5, 0.5, -0.5, -1.5};
1050  const std::vector<double> offset25 = {0.5, -0.5};
1051  std::vector<double> offset = {};
1052 
1053  if (absEta > 3.2) {
1054  // Fill four bins in phi
1055  phiMod = std::floor(phiMod/4)*4. + 2.;
1056  offset = offset32;
1057  monJE.etaScaled.push_back(signeta*4.7);
1058  monJE.etaScaled.push_back(signeta*3.7);
1059  monJE.etaScaled.push_back(signeta*3.5);
1060 
1061  }
1062  else if(absEta > 2.9) {
1063  phiMod = std::floor(phiMod/2)*2. + 1.;
1064  offset = offset25;
1065  monJE.etaScaled.push_back(signeta*3.15);
1066  }
1067 
1068 
1069  if (absEta > 2.5) {
1070  // Fill two bins in phi
1071  phiMod = std::floor(phiMod/2)*2. + 1.;
1072  offset = offset25;
1073  monJE.etaScaled.push_back(etaMod);
1074  }
1075  else {
1076  offset = {0.};
1077  monJE.etaScaled.push_back(etaMod);
1078  }
1079 
1080 
1081  // Fill the histograms
1082  for (auto phiOffset : offset) {
1083  monJE.phiScaled.push_back(phiMod + phiOffset);
1084  }
1085 
1086  vecMonJE.push_back(monJE);
1087 
1088  return StatusCode::SUCCESS;
1089 }
1090 
1091 
1093  const std::string& groupName,
1094  const std::string& weightName,
1095  double weight) const {
1096 
1097 
1098  double phiMod = monTT.phiScaled; // Integer binning for 2D plots
1099  double etaMod = monTT.tower->eta();
1100  const double absEta = std::abs(etaMod);
1101 
1102  const std::vector<double> offset32 = {1.5, 0.5, -0.5, -1.5};
1103  const std::vector<double> offset25 = {0.5, -0.5};
1104  std::vector<double> offset = {};
1105 
1106  if (absEta > 3.2) {
1107  // Fill four bins in phi
1108  phiMod = std::floor(phiMod/4)*4. + 2.;
1109  offset = offset32;
1110  }
1111  else if (absEta > 2.5) {
1112  // Fill two bins in phi
1113  phiMod = std::floor(phiMod/2)*2. + 1.;
1114  offset = offset25;
1115  }
1116  else {
1117  offset = {0.};
1118  }
1119 
1120  ATH_MSG_DEBUG("absEta: " << absEta << "offset.size(): " << offset.size());
1121 
1122  // Fill the histograms
1123  for (auto phiOffset : offset) {
1124 
1125  auto etaTT_2D = Monitored::Scalar<double>("etaTT_2D", etaMod);
1126  auto phiTT_2D = Monitored::Scalar<double>("phiTT_2D", phiMod + phiOffset);
1127 
1128  auto weight_2D = Monitored::Scalar<double>(weightName, weight); // Weight for filling 2D profile histograms; name must be included in python histogram definition
1129  ATH_MSG_DEBUG("groupName: weight_2D" << weight_2D);
1130 
1131  fill(groupName, etaTT_2D, phiTT_2D, weight_2D);
1132 
1133  }
1134 
1135  return StatusCode::SUCCESS;
1136 }
1137 
1138 
1139 bool MistimedStreamMonitorAlgorithm::pulseQuality(const std::vector<uint16_t>& ttPulse, int peakSlice) const {
1140 
1141  bool goodPulse = true;
1142  int size = ttPulse.size();
1143  if (peakSlice > size) {
1144  ATH_MSG_ERROR("Peak Slice " << peakSlice << " supress the ttPulse vector size " << size );
1145  goodPulse = false;
1146  return goodPulse;
1147  }
1148  if (size < 1) {
1149  ATH_MSG_ERROR("The ttPulse vector size " << size << " not valid for Peak Slice " << peakSlice );
1150  goodPulse = false;
1151  return goodPulse;
1152  }
1153  int a = ttPulse[peakSlice-1];
1154  int b = ttPulse[peakSlice];
1155  int c = ttPulse[peakSlice+1];
1156  double tim = (0.5*a-0.5*c)/(a+c-2*b);
1157  double wid = (a+c-64.0)/(b-32.0);
1158  if ( tim < 0.0 ) goodPulse = false;
1159  else if ( tim > 0.3 ) goodPulse = false;
1160  if ( wid < 1.0 ) goodPulse = false;
1161  else if ( wid > 1.6 ) goodPulse = false;
1162 
1163  ATH_MSG_DEBUG("Pulse qual= "<< goodPulse<<" tim = "<<tim<<" wid = "<<wid);
1164  ATH_MSG_DEBUG("a = "<< a <<" b = "<<b<<" c = "<<c);
1165 
1166  return goodPulse;
1167 }
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
MistimedStreamMonitorAlgorithm::m_maxEvents
Gaudi::Property< int > m_maxEvents
Definition: MistimedStreamMonitorAlgorithm.h:149
MistimedStreamMonitorAlgorithm.h
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
L1CaloReadoutConfigJSON::l1aFadcSlice
unsigned int l1aFadcSlice() const
Definition: L1CaloReadoutConfigJSON.h:21
xAOD::jFexTauRoI_v1
Class describing properties of a LVL1 jFEX global Trigger Object (TOB) in the xAOD format.
Definition: jFexTauRoI_v1.h:23
xAOD::jFexSRJetRoI_v1
Class describing properties of a LVL1 jFEX global Trigger Object (TOB) in the xAOD format.
Definition: jFexSRJetRoI_v1.h:23
MistimedStreamMonitorAlgorithm::badpeakTT
@ badpeakTT
Definition: MistimedStreamMonitorAlgorithm.h:163
MistimedStreamMonitorAlgorithm::fillHistograms
virtual StatusCode fillHistograms(const EventContext &ctx) const override
adds event to the monitoring histograms
Definition: MistimedStreamMonitorAlgorithm.cxx:56
MistimedStreamMonitorAlgorithm::MistimedStreamMonitorAlgorithm
MistimedStreamMonitorAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Definition: MistimedStreamMonitorAlgorithm.cxx:12
xAOD::CPMTower_v2::phi
float phi() const
get phi (note that for L1Calo phi runs from 0 to 2pi)
MistimedStreamMonitorAlgorithm::m_mutex
std::mutex m_mutex
Definition: MistimedStreamMonitorAlgorithm.h:154
MistimedStreamMonitorAlgorithm::m_ttTool
ToolHandle< LVL1::IL1TriggerTowerToolRun3 > m_ttTool
Definition: MistimedStreamMonitorAlgorithm.h:121
xAOD::jFexTauRoI_v1::eta
float eta() const
MistimedStreamMonitorAlgorithm::MonitorJE::element
const xAOD::JetElement * element
Definition: MistimedStreamMonitorAlgorithm.h:80
SG::ReadCondHandle
Definition: ReadCondHandle.h:44
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
MistimedStreamMonitorAlgorithm::m_eFexTauContainerKey
SG::ReadHandleKey< xAOD::eFexTauRoIContainer > m_eFexTauContainerKey
Definition: MistimedStreamMonitorAlgorithm.h:107
SG::Accessor< float >
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
MistimedStreamMonitorAlgorithm::MonitorJE::etaScaled
std::vector< double > etaScaled
Definition: MistimedStreamMonitorAlgorithm.h:82
L1CaloReadoutConfigContainerJSON::readoutConfigJSON
const L1CaloReadoutConfigJSON * readoutConfigJSON(unsigned int channelId) const
Definition: L1CaloReadoutConfigContainerJSON.cxx:237
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
MistimedStreamMonitorAlgorithm::EtaPhiOverlap
@ EtaPhiOverlap
Definition: MistimedStreamMonitorAlgorithm.h:169
MistimedStreamMonitorAlgorithm::m_uselegacy
Gaudi::Property< bool > m_uselegacy
Definition: MistimedStreamMonitorAlgorithm.h:125
xAOD::CPMTower_v2::eta
float eta() const
get eta
xAOD::JetElement_v2
Description of JetElement_v2.
Definition: JetElement_v2.h:26
RunTileMonitoring.groupName
groupName
Definition: RunTileMonitoring.py:158
MistimedStreamMonitorAlgorithm::lateTT
@ lateTT
Definition: MistimedStreamMonitorAlgorithm.h:166
PlotCalibFromCool.begin
begin
Definition: PlotCalibFromCool.py:94
M_PI
#define M_PI
Definition: ActiveFraction.h:11
SG::ReadCondHandle::isValid
bool isValid()
Definition: ReadCondHandle.h:206
xAOD::gFexJetRoIContainer
gFexJetRoIContainer_v1 gFexJetRoIContainer
Definition: gFexJetRoIContainer.h:15
MistimedStreamMonitorAlgorithm::m_runParametersContainer
SG::ReadCondHandleKey< L1CaloRunParametersContainer > m_runParametersContainer
Definition: MistimedStreamMonitorAlgorithm.h:129
MistimedStreamMonitorAlgorithm::TTEMLayer
@ TTEMLayer
Definition: MistimedStreamMonitorAlgorithm.h:168
xAOD::jFexTowerContainer
jFexTowerContainer_v1 jFexTowerContainer
Define the latest version of the TriggerTower container.
Definition: jFexTowerContainer.h:14
xAOD::jFexSRJetRoI_v1::eta
float eta() const
xAOD::jFexSRJetRoI_v1::phi
float phi() const
MistimedStreamMonitorAlgorithm::m_usephaseI
Gaudi::Property< bool > m_usephaseI
Definition: MistimedStreamMonitorAlgorithm.h:126
xAOD::jFexSRJetRoI_v1::tobWord
uint32_t tobWord() const
The "raw" 32-bit word describing the object candidate.
MistimedStreamMonitorAlgorithm::m_eFexEMContainerKey
SG::ReadHandleKey< xAOD::eFexEMRoIContainer > m_eFexEMContainerKey
Definition: MistimedStreamMonitorAlgorithm.h:106
xAOD::JetElement_v2::eta
float eta() const
get eta
MistimedStreamMonitorAlgorithm::m_gFexJetTobKeyList
SG::ReadHandleKeyArray< xAOD::gFexJetRoIContainer > m_gFexJetTobKeyList
Definition: MistimedStreamMonitorAlgorithm.h:119
CTP_Decoder
Definition: CTP_Decoder.h:141
CTP_RDO::getNumberOfBunches
uint32_t getNumberOfBunches() const
Definition: CTP_RDO.cxx:89
dqt_zlumi_pandas.weight
int weight
Definition: dqt_zlumi_pandas.py:189
AthMonitorAlgorithm
Base class for Athena Monitoring Algorithms.
Definition: AthMonitorAlgorithm.h:36
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
AthCommonDataStore< AthCommonMsg< Gaudi::Algorithm > >::evtStore
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:85
MistimedStreamMonitorAlgorithm::badCentralTT
@ badCentralTT
Definition: MistimedStreamMonitorAlgorithm.h:164
MistimedStreamMonitorAlgorithm::MonitorTT
Struct to contain PPM trigger tower info.
Definition: MistimedStreamMonitorAlgorithm.h:64
MistimedStreamMonitorAlgorithm::MonitorTT::phi1d
double phi1d
phi for 2d maps with integer bins (taking into account granularity in eta)
Definition: MistimedStreamMonitorAlgorithm.h:67
jet
Definition: JetCalibTools_PlotJESFactors.cxx:23
MistimedStreamMonitorAlgorithm::MonitorCPM::tower
const xAOD::CPMTower * tower
Definition: MistimedStreamMonitorAlgorithm.h:72
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
L1CaloRunParametersContainer::runParameters
const L1CaloRunParameters * runParameters(unsigned int channelId) const
Definition: L1CaloRunParametersContainer.cxx:93
MistimedStreamMonitorAlgorithm::fillPPMEtaPhi
StatusCode fillPPMEtaPhi(MonitorTT &monTT, const std::string &groupName, const std::string &weightName, double weight) const
Definition: MistimedStreamMonitorAlgorithm.cxx:1092
xAOD::jFexTauRoI_v1::tobEt
uint16_t tobEt() const
MistimedStreamMonitorAlgorithm::All
@ All
Definition: MistimedStreamMonitorAlgorithm.h:159
MistimedStreamMonitorAlgorithm::L1_Trigger
@ L1_Trigger
Definition: MistimedStreamMonitorAlgorithm.h:162
L1CaloReadoutConfigJSON::numFadcSlices
unsigned int numFadcSlices() const
Definition: L1CaloReadoutConfigJSON.h:20
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
TauGNNUtils::Variables::Track::dPhi
bool dPhi(const xAOD::TauJet &tau, const xAOD::TauTrack &track, double &out)
Definition: TauGNNUtils.cxx:538
xAOD::gFexJetRoI_v1
Class describing properties of a LVL1 gFEX jet Trigger Object (TOB) in the xAOD format.
Definition: gFexJetRoI_v1.h:25
xAOD::jFexSRJetRoI_v1::tobEt
uint16_t tobEt() const
xAOD::TriggerTower_v2
Description of TriggerTower_v2.
Definition: TriggerTower_v2.h:49
xAOD::jFexTauRoI_v1::tobWord
uint32_t tobWord() const
The "raw" 32-bit word describing the object candidate.
MistimedStreamMonitorAlgorithm::m_xAODTriggerTowerContainerName
SG::ReadHandleKey< xAOD::TriggerTowerContainer > m_xAODTriggerTowerContainerName
container keys including steering parameter and description
Definition: MistimedStreamMonitorAlgorithm.h:100
MistimedStreamMonitorAlgorithm::makeTowerJE
StatusCode makeTowerJE(const xAOD::JetElement *je, std::vector< MonitorJE > &vecMonJE) const
Definition: MistimedStreamMonitorAlgorithm.cxx:1029
xAOD::TriggerTower_v2::eta
virtual double eta() const final
The pseudorapidity ( ) of the particle.
Definition: TriggerTower_v2.cxx:210
MistimedStreamMonitorAlgorithm::MonitorTT::tower
const xAOD::TriggerTower * tower
Definition: MistimedStreamMonitorAlgorithm.h:65
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
xAOD::jFexSRJetRoI
jFexSRJetRoI_v1 jFexSRJetRoI
Define the latest version of the jFexSRJetRoI class
Definition: jFexSRJetRoI.h:14
CHECK
#define CHECK(...)
Evaluate an expression and check for errors.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:422
xAOD::jFexTauRoI_v1::phi
float phi() const
AthMonitorAlgorithm::fill
void fill(const ToolHandle< GenericMonitoringTool > &groupHandle, std::vector< std::reference_wrapper< Monitored::IMonitoredVariable >> &&variables) const
Fills a vector of variables to a group by reference.
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
MistimedStreamMonitorAlgorithm::badLateTT
@ badLateTT
Definition: MistimedStreamMonitorAlgorithm.h:165
AthMonitorAlgorithm::GetEventInfo
SG::ReadHandle< xAOD::EventInfo > GetEventInfo(const EventContext &) const
Return a ReadHandle for an EventInfo object (get run/event numbers, etc.)
Definition: AthMonitorAlgorithm.cxx:107
DataVector
Derived DataVector<T>.
Definition: DataVector.h:794
MistimedStreamMonitorAlgorithm::m_trigDec
PublicToolHandle< Trig::TrigDecisionTool > m_trigDec
Definition: MistimedStreamMonitorAlgorithm.h:95
SG::ReadHandle::isValid
virtual bool isValid() override final
Can the handle be successfully dereferenced?
MistimedStreamMonitorAlgorithm::m_packageName
StringProperty m_packageName
Definition: MistimedStreamMonitorAlgorithm.h:89
MistimedStreamMonitorAlgorithm::m_eventCounter
std::atomic< int > m_eventCounter
Definition: MistimedStreamMonitorAlgorithm.h:152
MistimedStreamMonitorAlgorithm::m_ctpRdoReadKey
SG::ReadHandleKey< CTP_RDO > m_ctpRdoReadKey
Definition: MistimedStreamMonitorAlgorithm.h:97
MistimedStreamMonitorAlgorithm::m_jFexSRJetContainerKey
SG::ReadHandleKey< xAOD::jFexSRJetRoIContainer > m_jFexSRJetContainerKey
Definition: MistimedStreamMonitorAlgorithm.h:112
MistimedStreamMonitorAlgorithm::MonitorJE::phiScaled
std::vector< double > phiScaled
Definition: MistimedStreamMonitorAlgorithm.h:81
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:228
MistimedStreamMonitorAlgorithm::m_jetElementLocation
SG::ReadHandleKey< xAOD::JetElementContainer > m_jetElementLocation
Definition: MistimedStreamMonitorAlgorithm.h:104
xAOD::gFexJetRoI
gFexJetRoI_v1 gFexJetRoI
Define the latest version of the gFexJetRoI class.
Definition: gFexJetRoI.h:16
MistimedStreamMonitorAlgorithm::m_EmulTowerKey
SG::ReadHandleKey< xAOD::jFexTowerContainer > m_EmulTowerKey
Definition: MistimedStreamMonitorAlgorithm.h:116
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
MistimedStreamMonitorAlgorithm::pulseQuality
bool pulseQuality(const std::vector< uint16_t > &ttPulse, int peakSlice) const
Definition: MistimedStreamMonitorAlgorithm.cxx:1139
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
SG::CondHandleKey::initialize
StatusCode initialize(bool used=true)
MistimedStreamMonitorAlgorithm::makeTowerCPM
StatusCode makeTowerCPM(const xAOD::CPMTower *cpm, std::vector< MonitorCPM > &vecMonCPM) const
Definition: MistimedStreamMonitorAlgorithm.cxx:981
SG::VarHandleBase::key
virtual const std::string & key() const override final
Return the StoreGate ID for the referenced object.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleBase.cxx:64
MistimedStreamMonitorAlgorithm::m_jFexDataTowerKey
SG::ReadHandleKey< xAOD::jFexTowerContainer > m_jFexDataTowerKey
Definition: MistimedStreamMonitorAlgorithm.h:115
CTP_RDO::getL1AcceptBunchPosition
uint32_t getL1AcceptBunchPosition() const
Definition: CTP_RDO.cxx:94
TriggerTest.ctp
ctp
Retrieve trigger EDM objects.
Definition: TriggerTest.py:14
MistimedStreamMonitorAlgorithm::InTime
@ InTime
Definition: MistimedStreamMonitorAlgorithm.h:167
AthMonitorAlgorithm::initialize
virtual StatusCode initialize() override
initialize
Definition: AthMonitorAlgorithm.cxx:18
CTP_RDO
Definition: CTP_RDO.h:20
MistimedStreamMonitorAlgorithm::MonitorCPM::etaScaled
double etaScaled
Definition: MistimedStreamMonitorAlgorithm.h:74
MistimedStreamMonitorAlgorithm::MonitorCPM
Struct to contain CPM tower info.
Definition: MistimedStreamMonitorAlgorithm.h:71
a
TList * a
Definition: liststreamerinfos.cxx:10
MistimedStreamMonitorAlgorithm::m_eFexEMOutContainerKey
SG::ReadHandleKey< xAOD::eFexEMRoIContainer > m_eFexEMOutContainerKey
Definition: MistimedStreamMonitorAlgorithm.h:108
MistimedStreamMonitorAlgorithm::MonitorTT::phiScaled
double phiScaled
Definition: MistimedStreamMonitorAlgorithm.h:66
ReadFloatFromCool.adc
adc
Definition: ReadFloatFromCool.py:48
MistimedStreamMonitorAlgorithm::HLT_mistimemonj400
@ HLT_mistimemonj400
Definition: MistimedStreamMonitorAlgorithm.h:161
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
MistimedStreamMonitorAlgorithm::MonitorJE
Struct to contain JE info.
Definition: MistimedStreamMonitorAlgorithm.h:79
MistimedStreamMonitorAlgorithm::m_jFexTauContainerKey
SG::ReadHandleKey< xAOD::jFexTauRoIContainer > m_jFexTauContainerKey
Definition: MistimedStreamMonitorAlgorithm.h:113
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
TauGNNUtils::Variables::absEta
bool absEta(const xAOD::TauJet &tau, double &out)
Definition: TauGNNUtils.cxx:234
xAOD::jFexTauRoI
jFexTauRoI_v1 jFexTauRoI
Define the latest version of the jFexSRJetRoI class
Definition: jFexTauRoI.h:13
xAOD::JetElement_v2::phi
float phi() const
get phi (note that for L1Calo phi runs from 0 to 2pi)
MistimedStreamMonitorAlgorithm::m_jFexLRJetContainerKey
SG::ReadHandleKey< xAOD::jFexLRJetRoIContainer > m_jFexLRJetContainerKey
Definition: MistimedStreamMonitorAlgorithm.h:111
MistimedStreamMonitorAlgorithm::m_cpmTowerLocation
SG::ReadHandleKey< xAOD::CPMTowerContainer > m_cpmTowerLocation
Definition: MistimedStreamMonitorAlgorithm.h:102
ConstAccessor.h
Helper class to provide constant type-safe access to aux data.
Monitored::Scalar
Declare a monitored scalar variable.
Definition: MonitoredScalar.h:34
fillSCTHists.etaMod
etaMod
Definition: fillSCTHists.py:23
MistimedStreamMonitorAlgorithm::MonitorCPM::phiScaled
std::vector< double > phiScaled
Definition: MistimedStreamMonitorAlgorithm.h:73
xAOD::jFexTower_v1
Class describing input data of a LVL1 jFEX.
Definition: jFexTower_v1.h:22
SG::get
const T * get(const ReadHandleKey< T > &key)
Convenience function to retrieve an object given a ReadHandleKey.
TauGNNUtils::Variables::Track::dEta
bool dEta(const xAOD::TauJet &tau, const xAOD::TauTrack &track, double &out)
Definition: TauGNNUtils.cxx:527
MistimedStreamMonitorAlgorithm::initialize
virtual StatusCode initialize() override
initialize
Definition: MistimedStreamMonitorAlgorithm.cxx:17
L1CaloReadoutConfigJSON::channelId
unsigned int channelId() const
Definition: L1CaloReadoutConfigJSON.h:18
L1CaloRunParameters::readoutConfigID
unsigned int readoutConfigID() const
Definition: L1CaloRunParameters.h:29
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
TileDCSDataPlotter.tt
tt
Definition: TileDCSDataPlotter.py:874
MistimedStreamMonitorAlgorithm::m_phiScaleTT
Gaudi::Property< double > m_phiScaleTT
Definition: MistimedStreamMonitorAlgorithm.h:124
python.compressB64.c
def c
Definition: compressB64.py:93
MistimedStreamMonitorAlgorithm::makeTowerPPM
StatusCode makeTowerPPM(const xAOD::TriggerTower *tt, std::vector< MonitorTT > &vecMonTT) const
Helper functions.
Definition: MistimedStreamMonitorAlgorithm.cxx:961
MistimedStreamMonitorAlgorithm::m_readoutConfigContainerJSON
SG::ReadCondHandleKey< L1CaloReadoutConfigContainerJSON > m_readoutConfigContainerJSON
Definition: MistimedStreamMonitorAlgorithm.h:130
xAOD::TriggerTower
TriggerTower_v2 TriggerTower
Define the latest version of the TriggerTower class.
Definition: Event/xAOD/xAODTrigL1Calo/xAODTrigL1Calo/TriggerTower.h:16
L1CaloReadoutConfigJSON::readout80ModePpm
unsigned int readout80ModePpm() const
Definition: L1CaloReadoutConfigJSON.h:68
MistimedStreamMonitorAlgorithm::UnsuitableReadout
@ UnsuitableReadout
Definition: MistimedStreamMonitorAlgorithm.h:160
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37
xAOD::CPMTower_v2
Description of CPMTower_v2.
Definition: CPMTower_v2.h:26