ATLAS Offline Software
Loading...
Searching...
No Matches
eTowerMakerFromEfexTowers.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
7
12
15
16#undef R__HAS_VDT
17#include "ROOT/RVec.hxx"
18
19#include "TFile.h"
20#include "TTree.h"
22#include "TH2D.h"
23#include "TROOT.h"
24#include "TCanvas.h"
25#include "TBox.h"
26
27namespace LVL1 {
28
29 eTowerMakerFromEfexTowers::eTowerMakerFromEfexTowers(const std::string& name, ISvcLocator* pSvcLocator)
30 : AthReentrantAlgorithm(name, pSvcLocator)
31 {
32
33 }
34
35
37{
38 ATH_CHECK( m_eTowerBuilderTool.retrieve() );
41 ATH_CHECK( m_eTowerContainerSGKey.initialize() );
43
44 if (!m_noiseCutsKey.empty()) {
45 // disable built-in noise cuts because will be loading them from conditions db instead
47 }
48
49 return StatusCode::SUCCESS;
50}
51
52
53 StatusCode eTowerMakerFromEfexTowers::execute(const EventContext& ctx) const
54{
55 // load noise cuts .. should really only need to do this at start of runs, not every event!
56 std::map<std::pair<int, int>, int> noiseCutsMap; // key is [eta,layer]
57 bool useHardcodedCuts = false;
58 if(!m_noiseCutsKey.empty()) {
59 // check timestamp of event is not *before* date when started using database
60 if (ctx.eventID().time_stamp() < m_noiseCutBeginTimestamp) {
61 useHardcodedCuts = true;
62 } else {
63 SG::ReadCondHandle <CondAttrListCollection> noiseCuts{m_noiseCutsKey, ctx};
64 if (noiseCuts.isValid()) {
65 if(msgLvl(MSG::DEBUG) && !m_printedNoiseCuts) {
66 m_printedNoiseCuts = true;
67 ATH_MSG_DEBUG("DB Noise cuts are:");
68 noiseCuts->dump();
69 }
70 if(noiseCuts->size()==0) {
71 ATH_MSG_ERROR("No noise cuts loaded from conditions db for event with timestamp" << ctx.eventID().time_stamp());
72 return StatusCode::FAILURE;
73 }
74 for (auto itr = noiseCuts->begin(); itr != noiseCuts->end(); ++itr) {
75 if (itr->first >= 50) continue;
76 noiseCutsMap[std::pair(itr->first, 0)] = itr->second["EmPS"].data<int>();
77 noiseCutsMap[std::pair(itr->first, 1)] = itr->second["EmFR"].data<int>();
78 noiseCutsMap[std::pair(itr->first, 2)] = itr->second["EmMD"].data<int>();
79 noiseCutsMap[std::pair(itr->first, 3)] = itr->second["EmBK"].data<int>();
80 noiseCutsMap[std::pair(itr->first, 4)] = (itr->first >= 10 && itr->first < 40)
81 ? itr->second["Tile"].data<int>()
82 : itr->second["HEC"].data<int>();
83 }
84 }
85 }
86 }
87
88 // STEP 0 - Make a fresh local eTowerContainer
89 std::unique_ptr<eTowerContainer> local_eTowerContainerRaw = std::make_unique<eTowerContainer>();
90
91 // STEP 1 - Make some eTowers and fill the local container
92 m_eTowerBuilderTool->init(local_eTowerContainerRaw);
93 local_eTowerContainerRaw->clearContainerMap();
94 local_eTowerContainerRaw->fillContainerMap();
95
97 // we may have DataTowers because of error statuses ... so don't use the primary towers if
98 // they all have errors
99 size_t badTowers = 0;
100 if(eFexTowers.isValid()) {
101 for(auto eFexTower : *eFexTowers) {
102 if(eFexTower->em_status()||eFexTower->had_status()) badTowers++;
103 }
104 }
105 if((!eFexTowers.isValid() || eFexTowers->size() < m_minTowersRequired || eFexTowers->size()==badTowers) && !m_eFexTowerContainer2SGKey.empty()) {
107 // removing this to avoid breaking frozen tier0 policy
108 // bug keeping commented out until sure we've replaced with a good alternative
109 //const xAOD::EventInfo* ei = nullptr;
110 //CHECK( evtStore()->retrieve(ei) );
111 //ei->auxdecor<bool>("eTowerMakerFromEfexTowers_usedSecondary") = true;
112 }
113
114 // STEP 2 - Do the efexTower-tower mapping - put this information into the eTowerContainer
115 for(auto eFexTower : *eFexTowers) {
116 // need to ensure this eFexTower is a "core" tower in a module ... so that there aren't disconnected inputs
117 // and also need to only do one tower per location, of course
118 auto tower = local_eTowerContainerRaw->findTower(eFexTower->eFEXtowerID());
119 auto counts = eFexTower->et_count();
120 for(size_t i=0;i<counts.size();i++) {
121 if(i<10 && eFexTower->em_status()) continue; // bad status bits have their energy zerod by the firmware
122 if(i==10 && eFexTower->had_status()) continue;
123 if (eFexTower->disconnectedCount(i)) continue;
124 if (counts.at(i)==0 || (counts.at(i)>1020 && counts.at(i)!=1023)) continue; // absent (1025 from BS decoder), invalid (1022), empty (0) or masked (0) channel
125 // special case logic for reordering |eta|=2.5 and overlap
126 // and l1 1.8-2.0 ... need to put the merged sc counts into slots that wont be split
127 int layer; int cell=i;
128 if(i<1 || (i==4 && std::abs(eFexTower->eta()+0.025)>2.4)) {layer = 0;cell=0;}
129 else if(i<5) layer = 1;
130 else if(i<9) layer = 2;
131 else if(i<10) layer = 3;
132 else layer = 4;
133
134 // apply noise cut ... for runs up to 14th April 2023 was killing with <, then from run 449180 onwards kills with <=
135 // since long-term behaviour is latter, will use that
136 //if(useHardcodedCuts && !eFEXCompression::noiseCut(counts.at(i),layer,true)) continue;
137 if(!useHardcodedCuts && counts.at(i) <= noiseCutsMap[std::pair( int( (eFexTower->eta() + 2.525)/0.1 ), layer)]) continue;
138
139 // checking we haven't already filled this tower (happens when using efexDataTowers ... multiple towers per loc for different modules)
140 // this is ugly as ...
141 if(!tower->getET_float(layer,cell-(layer==1)*1-(layer==2)*5-(layer==3)*9-(layer==4)*10)) {
142 // if tile then count is in steps of 500 MeV, not in latome multilinear encoding
143 bool isTile = (std::abs(eFexTower->eta()+0.025)<1.5 && layer==4);
144 tower->setET(cell,isTile ? (counts.at(i)*500.) : eFEXCompression::expand(counts.at(i)),layer + isTile, useHardcodedCuts);
145 }
146 }
147 }
148
149 if(msgLvl(MSG::DEBUG)) {
150 std::scoped_lock lock(m_debugMutex);
151 // dump towers to histograms
152 // counts are the "codes" of multi-scale latome, or tile count
153
154 TFile *debugFile = dynamic_cast<TFile *>(gROOT->GetListOfFiles()->FindObject("debug_eFexTowerMakerFromEfexTowers.root"));
155 if (!debugFile) debugFile = TFile::Open("debug_eFexTowerMakerFromEfexTowers.root", "RECREATE");
156 if (debugFile->GetListOfKeys()->GetEntries() < 20) {
157 TDirectory *dir = gDirectory;
158 debugFile->cd();
159 TH2D ps("ps", "ps [code];#eta;#phi", 50, -2.5, 2.5, 64, -M_PI, M_PI);
160 TH2D l1("l1", "l1 [code];#eta;#phi", 200, -2.5, 2.5, 64, -M_PI, M_PI);
161 TH2D l2("l2", "l2 [code];#eta;#phi", 200, -2.5, 2.5, 64, -M_PI, M_PI);
162 TH2D l3("l3", "l3 [code];#eta;#phi", 50, -2.5, 2.5, 64, -M_PI, M_PI);
163 TH2D had("had", "had [code~25MeV or 500MeV for tile];#eta;#phi", 50, -2.5, 2.5, 64, -M_PI, M_PI);
164 std::vector < TH1 * > hists{&ps, &l1, &l2, &l3, &had};
165 for(auto eFexTower : *eFexTowers) {
166 auto counts = eFexTower->et_count();
167 if (counts.empty()) continue;
168 int etaIndex = int( (eFexTower->eta()+0.025)*10 ) + (((eFexTower->eta()+0.025)<0) ? -1 : 1); // runs from -25 to 25 (excluding 0)
169 int phiIndex = int( (eFexTower->phi()+0.025)*32./M_PI ) + ((eFexTower->phi()+0.025)<0 ? -1 : 1); // runs from -32 to 32 (excluding 0)
170 double tEta = ((etaIndex < 0 ? 0.5 : -0.5) + etaIndex - 0.5) * 0.1; // left edge
171 double tPhi = ((phiIndex < 0 ? 0.5 : -0.5) + phiIndex) * M_PI / 32; // centre
172 for(size_t i=0;i<counts.size();i++) {
173 if(i<10 && eFexTower->em_status()) continue; // bad status bits have their energy zerod by the firmware
174 if(i==10 && eFexTower->had_status()) continue;
175 if (eFexTower->disconnectedCount(i)) continue;
176 int layer; int cell=i;
177 if(i<1 || (i==4 && std::abs(eFexTower->eta()+0.025)>2.4)) {layer = 0;cell=0;}
178 else if(i<5) {layer = 1;cell = i-1;}
179 else if(i<9) {layer = 2;cell = i-5;}
180 else if(i<10) {layer = 3;cell=0;}
181 else {layer = 4;cell=0;}
182 if(!useHardcodedCuts && counts.at(i) <= noiseCutsMap[std::pair( int( (eFexTower->eta() + 2.525)/0.1 ), layer)]) continue;
183 hists.at(layer)->SetBinContent(hists.at(layer)->FindFixBin(tEta + 0.025 * cell + 0.0125, tPhi),counts.at(i));
184
185 }
186 }
187
188 TCanvas c;
189 c.SetName(TString::Format("evt%lu", ctx.eventID().event_number()));
190 c.SetTitle(TString::Format("Run %u LB %u Event %lu", ctx.eventID().run_number(), ctx.eventID().lumi_block(),
191 ctx.eventID().event_number()));
192 c.Divide(2, 3);
193 TH2D tobs("tobs", "Sum [MeV];#eta;#phi", 50, -2.5, 2.5, 64, -M_PI, M_PI);
194 for (size_t i = 0; i < hists.size(); i++) {
195 c.GetPad(i + 1)->cd();gPad->SetGrid(1,1);
196 hists[i]->SetStats(false);
197 hists[i]->SetMarkerSize(2); // controls text size
198 hists[i]->GetXaxis()->SetRangeUser(-0.3, 0.3);
199 hists[i]->GetYaxis()->SetRangeUser(-0.3, 0.3);
200 hists[i]->Draw((hists[i]->GetNbinsX() > 50) ? "coltext89" : "coltext");
201 for (int ii = 1; ii <= hists[i]->GetNbinsX(); ii++) {
202 bool isTile = (i==4 && std::abs(hists[i]->GetXaxis()->GetBinCenter(ii))<1.5);
203 for (int jj = 1; jj <= hists[i]->GetNbinsY(); jj++)
204 tobs.Fill(hists[i]->GetXaxis()->GetBinCenter(ii), hists[i]->GetYaxis()->GetBinCenter(jj),
205 isTile ? (hists[i]->GetBinContent(ii, jj)*500.) : eFEXCompression::expand(hists[i]->GetBinContent(ii, jj)));
206 }
207 }
208 c.GetPad(hists.size() + 1)->cd();
209 tobs.SetStats(false);
210 tobs.Draw("col");
211 TBox b(-0.3, -0.3, 0.3, 0.3);
212 b.SetLineColor(kRed);
213 b.SetFillStyle(0);
214 b.SetLineWidth(1);
215 b.SetBit(TBox::kCannotMove);
216 tobs.GetListOfFunctions()->Add(b.Clone());
217 gPad->AddExec("onClick", TString::Format(
218 "{ auto pad = gPad->GetCanvas()->GetPad(%lu); if( pad->GetEvent()==kButton1Down ) { double x = pad->PadtoX(pad->AbsPixeltoX(pad->GetEventX())); double y = pad->PadtoY(pad->AbsPixeltoY(pad->GetEventY())); for(int i=1;i<%lu;i++) {auto h = dynamic_cast<TH1*>(gPad->GetCanvas()->GetPad(i)->GetListOfPrimitives()->At(1)); if(h) {h->GetXaxis()->SetRangeUser(x-0.3,x+0.3);h->GetYaxis()->SetRangeUser(y-0.3,y+0.3); } } if(auto b = dynamic_cast<TBox*>(pad->FindObject(\"tobs\")->FindObject(\"TBox\"))) {b->SetX1(x-0.3);b->SetX2(x+0.3);b->SetY1(y-0.3);b->SetY2(y+0.3);} gPad->GetCanvas()->Paint(); gPad->GetCanvas()->Update(); } }",
219 hists.size() + 1, hists.size() + 1));
220 c.Write();
221 gDirectory = dir;
222 }
223 }
224
225
226
227 // STEP 3 - Write the completed eTowerContainer into StoreGate (move the local copy in memory)
229 ATH_CHECK(eTowerContainerSG.record(std::move(/*my_eTowerContainerRaw*/local_eTowerContainerRaw)));
230
231 // STEP 4 - Close and clean the event
232 m_eTowerBuilderTool->reset();
233
234 return StatusCode::SUCCESS;
235}
236
237
238
239} // end of LVL1 namespace
#define M_PI
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_DEBUG(x)
Handle class for reading from StoreGate.
Handle class for recording to StoreGate.
bool msgLvl(const MSG::Level lvl) const
An algorithm that can be simultaneously executed in multiple threads.
static std::atomic< bool > s_disableNoiseCuts
static int expand(unsigned int code)
Uncompress data.
SG::ReadHandleKey< xAOD::eFexTowerContainer > m_eFexTowerContainer2SGKey
SG::ReadHandleKey< xAOD::eFexTowerContainer > m_eFexTowerContainerSGKey
UnsignedIntegerProperty m_noiseCutBeginTimestamp
SG::ReadCondHandleKey< CondAttrListCollection > m_noiseCutsKey
virtual StatusCode execute(const EventContext &ctx) const override
ToolHandle< IeTowerBuilder > m_eTowerBuilderTool
eTowerMakerFromEfexTowers(const std::string &name, ISvcLocator *pSvcLocator)
virtual StatusCode initialize() override
SG::WriteHandleKey< LVL1::eTowerContainer > m_eTowerContainerSGKey
virtual bool isValid() override final
Can the handle be successfully dereferenced?
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
uint32_t em_status() const
get em status bit
uint32_t had_status() const
setter for the above
uint32_t eFEXtowerID() const
setter for the above
const std::vector< uint16_t > & et_count() const
get Energy Counts
float phi() const
setter for the above
bool disconnectedCount(size_t idx) const
setter for the above
float eta() const
The pseudorapidity ( )
eFexTowerBuilder creates xAOD::eFexTowerContainer from supercells (LATOME) and triggerTowers (TREX) i...