ATLAS Offline Software
Loading...
Searching...
No Matches
FPGATrackSimLayerStudyTool.cxx
Go to the documentation of this file.
1// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
9
16#include "TH1D.h"
17#include "TH2D.h"
18#include "TTree.h"
19#include <algorithm>
20#include <bit>
21#include <numbers>
22
23FPGATrackSimLayerStudyTool::FPGATrackSimLayerStudyTool(const std::string& algname, const std::string &name, const IInterface *ifc) :
24 AthAlgTool(algname, name, ifc)
25{
26}
27
29{
30 // Dump the configuration to make sure it propagated through right
31 auto props = this->getProperties();
32 for( Gaudi::Details::PropertyBase* prop : props ) {
33 if (prop->ownerTypeName()==this->type()) {
34 ATH_MSG_DEBUG("Property:\t" << prop->name() << "\t : \t" << prop->toString());
35 }
36 }
37
38 ATH_CHECK(m_tHistSvc.retrieve());
39
41
42 return StatusCode::SUCCESS;
43
44}
45
47{
48 m_binnedhits = binnedhits;
49 const FPGATrackSimBinTool &bintool = m_binnedhits->getBinTool();
50 const IFPGATrackSimBinDesc* bindesc = bintool.binDesc();
51 int nLyrs = m_binnedhits->getNLayers();
52
53 // *Technically* this is a bit fragile. Since we are testing if the event selection service is set to
54 // the "skip truth" type rather than testing if it's set to the SingleMuon, SingleElectron, or SinglePion types.
55 // At the moment though we either set skip truth or we are running single particle, so it could be changed later.
57
58 // This is because if you change the binning class you can change what axis
59 // ranges you need for the plotting
60 ATH_MSG_INFO("Hist scales phi: " << m_phiScale << " eta: " << m_etaScale << " dr:" << m_drScale);
61
62 // Truth Parameter distributions, bounds should cover 3x nominal range
63 for (unsigned i = 0; i < FPGATrackSimTrackPars::NPARS; i++) {
65 m_truthpars_hists[i], ("truth" + bindesc->parNames(i)).c_str(),
66 (";" + m_binnedhits->getBinTool().binDesc()->parNames(i) + ";").c_str(), 2000,
67 -2 * m_binnedhits->getBinTool().parRange(i),
68 2 * m_binnedhits->getBinTool().parRange(i)));
69 }
70
71 // Data flow hists. We may not need these for the layer study.
72 ATH_CHECK(makeAndRegHist(m_inputHits, "InputHits", ";Input Hits", 200, 0, 100000));
74 &bintool.stepNames(), "hitsPerStep",
75 "; Hits per bin in step", 20, 0, m_isSingleParticle ? 50 : 10000));
76 ATH_CHECK(makeAndRegHist(m_hitsPerLayer, "hitsPerLayer", "; Layer ; Hits ", nLyrs, 0, nLyrs));
77 ATH_CHECK(makeAndRegHist(m_hitsPerLayer2D, "hitsPerLayer2D", "; Layer ; Hits ", nLyrs, 0, nLyrs, 20, 0, m_isSingleParticle ? 20 : 10000));
78 ATH_CHECK(makeAndRegHist(m_binsFilled, "binsFilled", "; Bins Filled per Event", 2000, 0, 2000));
79
80
81 // All Hit level histograms
82 ATH_CHECK(makeAndRegHistVector(m_rZ_allhits, nLyrs + 1, NULL, "RZ_allhits",
83 "; Z [mm] ; R [mm] ", 500, -2000, 2000, 500, 0, 500));
84
85 ATH_CHECK(makeAndRegHistVector(m_phiResidual, nLyrs + 1, NULL, "phiResidual",
86 "phi residual [mm]", 1000, -10, 10));
87 ATH_CHECK(makeAndRegHistVector(m_etaResidual, nLyrs + 1, NULL, "etaResidual",
88 "eta residual [mm]", 1000, -10, 10));
89
91 "; R[mm]; phi residual [mm]", 1200, 0, 1200, 1000, -100, 100));
93 "; R[mm]; eta residual [mm]", 1200, 0, 1200, 1000, -100, 100));
94
96 "; R[mm]; phi scale", 1200, 0, 1200, 1000, -2, 2.0));
98 "; R[mm]; eta scale", 1200, 0, 1200, 1000, -2.0, 2.0));
99
101 "phiTrueBinShift", "phi TrueBinShift [mm]", 1000, -10, 10));
103 "etaTrueBinShift", "eta TrueBinShift [mm]",1000, -10, 10));
104
105 // Road statistics
106 ATH_CHECK(makeAndRegHist(m_phiShift_road, "phiShift_road", ";Phi Shift", 2000, -m_phiScale, m_phiScale));
107 ATH_CHECK(makeAndRegHist(m_etaShift_road, "etaShift_road", ";Eta Shift", 2000, -m_etaScale, m_etaScale));
108 ATH_CHECK(makeAndRegHist(m_phiShift2D_road, "phiShift2D_road", ";Phi Shift; R", 400, -m_phiScale, m_phiScale, 100, 0, 400));
109 ATH_CHECK(makeAndRegHist(m_etaShift2D_road, "etaShift2D_road", ";Phi Shift; R", 400, -m_etaScale, m_etaScale, 100, 0, 400));
110
111 // Efficiency monitoring
113 "ptDist", "pT [GeV]",400, 0, 100));
115 "etaDist", "#eta",1000, -5, 5));
117 "phiDist", "#phi",640, 0, 2*std::numbers::pi));
119 "d0Dist", "d_{0} [mm]",120, -3.0, 3.0));
121 "z0Dist", "z_{0} [mm]",400, -200.0, 200.0));
122
123 return StatusCode::SUCCESS;
124}
125
126
128 ATH_MSG_DEBUG("Booking Layer Study Tree: " << m_layerStudyTreeName
129 << " and Truth Tree: " << m_truthTreeName);
130
131 // Create the LayerStudy tree
132 m_bin_tree = new TTree(m_layerStudyTreeName.value().c_str(),
133 m_layerStudyTreeName.value().c_str());
134 m_bin_tree->Branch("event", &m_bin_tree_event);
135 m_bin_tree->Branch("bin", &m_bin_tree_bin);
136 m_bin_tree->Branch("r", &m_bin_tree_r);
137 m_bin_tree->Branch("z", &m_bin_tree_z);
138 m_bin_tree->Branch("id", &m_bin_tree_id);
139 m_bin_tree->Branch("hash", &m_bin_tree_hash);
140 m_bin_tree->Branch("layer", &m_bin_tree_layer);
141 m_bin_tree->Branch("side", &m_bin_tree_side);
142 m_bin_tree->Branch("etamod", &m_bin_tree_etamod);
143 m_bin_tree->Branch("phimod", &m_bin_tree_phimod);
144 m_bin_tree->Branch("dettype", &m_bin_tree_dettype);
145 m_bin_tree->Branch("detzone", &m_bin_tree_detzone);
146
147 // Create the Truth tree
148 m_truth_tree = new TTree(m_truthTreeName.value().c_str(),
149 m_truthTreeName.value().c_str());
150 m_truth_tree->Branch("stdpars", &m_truth_tree_phi);
151 m_truth_tree->Branch("stdpars", &m_truth_tree_qOverPt);
152 m_truth_tree->Branch("stdpars", &m_truth_tree_eta);
153 m_truth_tree->Branch("stdpars", &m_truth_tree_d0);
154 m_truth_tree->Branch("stdpars", &m_truth_tree_z0);
155 m_truth_tree->Branch("parset", &m_truth_tree_parset);
156
157 // Register with THistSvc — convert Gaudi::Property to std::string before concatenation
158 ATH_CHECK(m_tHistSvc->regTree(m_dir.value() + m_layerStudyTreeName.value(), m_bin_tree));
159 ATH_CHECK(m_tHistSvc->regTree(m_dir.value() + m_truthTreeName.value(), m_truth_tree));
160
161 return StatusCode::SUCCESS;
162}
163
165{
166 m_bin_tree_bin.clear();
167 m_bin_tree_r.clear();
168 m_bin_tree_z.clear();
169 m_bin_tree_id.clear();
170 m_bin_tree_hash.clear();
171 m_bin_tree_layer.clear();
172 m_bin_tree_side.clear();
173 m_bin_tree_etamod.clear();
174 m_bin_tree_phimod.clear();
175 m_bin_tree_dettype.clear();
176 m_bin_tree_detzone.clear();
177
178 m_truth_tree_parset.clear();
179}
180
181void FPGATrackSimLayerStudyTool::fillBinLevelOutput ATLAS_NOT_THREAD_SAFE(const FPGATrackSimBinUtil::IdxSet &idx,
183{
184 setBinPlotsActive(idx);
185
186 // fill all truth
187 m_ptDist[0]->Fill(std::abs(1/m_truthpars.qOverPt));
188 m_etaDist[0]->Fill(1/m_truthpars.eta);
189 m_phiDist[0]->Fill(1/m_truthpars.phi);
190 m_d0Dist[0]->Fill(1/m_truthpars.d0);
191 m_z0Dist[0]->Fill(1/m_truthpars.z0);
192
193 if (m_binPlotsActive) {
194 for (auto& hit : data.hits) {
195 m_phiShift_road->Fill(hit.phiShift);
196 m_etaShift_road->Fill(hit.etaShift);
197 m_phiShift2D_road->Fill(hit.phiShift, hit.hitptr->getR());
198 m_etaShift2D_road->Fill(hit.etaShift, hit.hitptr->getR());
199 }
200
201 // fill param monitoring
202 for (int i = 0; i < 2; i++) {
203 // i=0 all, i=1 no missed layers, i=2 is one missed layer
204 if ((i == 0)|| (data.lyrCnt() >= m_binnedhits->getNLayers() - (i - 1))) {
205 // all layer hit
206 m_ptDist[i]->Fill(std::abs(1 / m_truthpars.qOverPt));
207 m_etaDist[i]->Fill(1 / m_truthpars.eta);
208 m_phiDist[i]->Fill(1 / m_truthpars.phi);
209 m_d0Dist[i]->Fill(1 / m_truthpars.d0);
210 m_z0Dist[i]->Fill(1 / m_truthpars.z0);
211 }
212 }
213
214 // Module mapping and Layer definition studies
215 // first sort hits by r+z radii
216 std::vector<FPGATrackSimBinUtil::StoredHit> sorted_hits = data.hits;
217 std::sort(sorted_hits.begin(), sorted_hits.end(),
218 [](const auto &hit1, const auto &hit2) {
219 return hit1.rzrad() < hit2.rzrad();
220 });
221
222 // Fill tree
223 ClearTreeVectors();
224 m_bin_tree_bin = std::vector<unsigned>(idx);
225 ATH_MSG_DEBUG("Output: Bin Tree bin" << idx);
226 for (auto &hit : sorted_hits) {
227 m_bin_tree_r.push_back(hit.hitptr->getR());
228 m_bin_tree_z.push_back(hit.hitptr->getZ());
229 m_bin_tree_id.push_back(hit.hitptr->getIdentifier());
230 m_bin_tree_hash.push_back(hit.hitptr->getIdentifierHash());
231 m_bin_tree_layer.push_back(hit.hitptr->getLayerDisk());
232 m_bin_tree_side.push_back(hit.hitptr->getSide());
233 m_bin_tree_etamod.push_back(hit.hitptr->getEtaModule());
234 m_bin_tree_phimod.push_back(hit.hitptr->getPhiModule());
235 m_bin_tree_dettype.push_back((int)hit.hitptr->getDetType());
236 m_bin_tree_detzone.push_back((int)hit.hitptr->getDetectorZone());
237 }
238 m_bin_tree->Fill();
239 m_binsFilledCnt++;
240 }
241}
242
243void FPGATrackSimLayerStudyTool::fillBinningSummary ATLAS_NOT_THREAD_SAFE(
244 const std::vector<std::shared_ptr<const FPGATrackSimHit>> &hits)
245{
246 m_inputHits->Fill(hits.size());
247
248 for (auto &step : m_binnedhits->getBinTool().steps()) {
249 for (auto bin : m_binnedhits->binnedHits()[step->stepNum()])
250 m_hitsPerStepBin[step->stepNum()]->Fill(bin.data().hitCnt);
251 }
252
253 for (auto bin :m_binnedhits->binnedHits()[m_binnedhits->getBinTool().lastStep()->stepNum()]) {
254 for (unsigned lyr = 0; lyr < m_binnedhits->getNLayers(); lyr++) {
255 unsigned cnt = bin.data().hitsInLyr(lyr);
256 m_hitsPerLayer->Fill(lyr, cnt);
257 m_hitsPerLayer2D->Fill(lyr, cnt);
258 }
259 }
260 m_binsFilled->Fill(m_binsFilledCnt);
261 m_binsFilledCnt=0;
262
263}
264
266 const IFPGATrackSimBinDesc* bindesc = m_binnedhits->getBinTool().binDesc();
267 m_rZ_allhits[m_binnedhits->getNLayers()]->Fill(hit->getZ(), hit->getR()); // all layer plot
268 if (m_truthIsValid)
269 {
270 m_etaResidual[m_binnedhits->getNLayers()]->Fill(bindesc->etaResidual(m_truthparset, hit));
271 m_phiResidual[m_binnedhits->getNLayers()]->Fill(bindesc->phiResidual(m_truthparset, hit));
272
273 int ptbin =
274 floor((m_truthpars[FPGATrackSimTrackPars::IHIP] + 1.0) / 2.0 * m_N_ptplot);
275 ptbin = std::min(std::max(ptbin,0),4);
276 m_etaResidual_v_r[ptbin]->Fill(hit->getR(), bindesc->etaResidual(m_truthparset, hit));
277 m_phiResidual_v_r[ptbin]->Fill(hit->getR(), bindesc->phiResidual(m_truthparset, hit));
278
280 double phiscale = -1.0*(hit->getGPhi()-m_truthpars[FPGATrackSimTrackPars::IPHI])/expectedshift;
281 m_phiScale_v_r[ptbin]->Fill(hit->getR(), phiscale);
282
283
285 FPGATrackSimBinUtil::ParSet binCenter = m_binnedhits->getBinTool().lastStep()->binCenter(m_truthbin.back());
286 m_etaTrueBinShift[m_binnedhits->getNLayers()]->Fill(bindesc->etaResidual(binCenter, hit));
287 m_phiTrueBinShift[m_binnedhits->getNLayers()]->Fill(bindesc->phiResidual(binCenter, hit));
288 }
289 }
290}
291
292
293
294void FPGATrackSimLayerStudyTool::parseTruthInfo ATLAS_NOT_THREAD_SAFE(std::vector<FPGATrackSimTruthTrack> const & truthtracks) {
295 ATH_MSG_DEBUG("In parseTruthInfo, truthtracks size = " << truthtracks.size());
296 m_truthIsValid = false;
297 m_bin_tree_event++;
298
299 const IFPGATrackSimBinDesc* bindesc = m_binnedhits->getBinTool().binDesc();
300
301 if (truthtracks.size() == 0) return;
302
303 // Convert to binning parameters and find truth bin for each step
304 m_truthpars = (truthtracks)[0].getPars();
305 m_truthpars[FPGATrackSimTrackPars::IHIP] =
306 m_truthpars[FPGATrackSimTrackPars::IHIP] * 1000;
307 m_truthparset = bindesc->trackParsToParSet(m_truthpars);
308 m_truthbin.clear();
309 for (auto &step : m_binnedhits->getBinTool().steps()) {
310 m_truthbin.push_back(step->binIdx(m_truthparset));
311 }
312
313 // histogram parameters
314 for (unsigned i = 0; i < FPGATrackSimTrackPars::NPARS; i++) {
315 m_truthpars_hists[i]->Fill(m_truthparset[i]);
316 }
317
318 // a closure test
319 FPGATrackSimTrackPars recovered = bindesc->parSetToTrackPars(m_truthparset);
320 ATH_MSG_DEBUG("parset:" << m_truthparset << " " << m_truthpars
321 << " ?= " << recovered << " closure:"
322 << " " << recovered[FPGATrackSimTrackPars::IHIP] - m_truthpars[FPGATrackSimTrackPars::IHIP]
323 << " " << recovered[FPGATrackSimTrackPars::IPHI] - m_truthpars[FPGATrackSimTrackPars::IPHI]
324 << " " << recovered[FPGATrackSimTrackPars::ID0] - m_truthpars[FPGATrackSimTrackPars::ID0]
325 << " " << recovered[FPGATrackSimTrackPars::IETA] - m_truthpars[FPGATrackSimTrackPars::IETA]
326 << " " << recovered[FPGATrackSimTrackPars::IZ0] - m_truthpars[FPGATrackSimTrackPars::IZ0]);
327
328 m_truth_tree_phi = m_truthpars[FPGATrackSimTrackPars::IPHI];
329 m_truth_tree_qOverPt = m_truthpars[FPGATrackSimTrackPars::IHIP];
330 m_truth_tree_d0 = m_truthpars[FPGATrackSimTrackPars::ID0];
331 m_truth_tree_z0 = m_truthpars[FPGATrackSimTrackPars::IZ0];
332 m_truth_tree_eta = m_truthpars[FPGATrackSimTrackPars::IETA];
333 m_truth_tree_parset = std::vector<double>(m_truthparset);
334 m_truth_tree->Fill();
335
336 // print if there are multiple tracks for debugging single track MC
337 if (truthtracks.size() > 1) {
338 for (unsigned i = 0; i < truthtracks.size(); i++) {
339 ATH_MSG_INFO("Multiple truth" << i << " of " << truthtracks.size()
340 << " " << (truthtracks)[i].getPars());
341 }
342 }
343
344 // find truth bin for later plotting selections
345 ATH_MSG_DEBUG("truthbin " << truthtracks.size()
346 << " " << m_truthpars << " " << m_truthbin);
347
348 // Check if the truth track falls in the binning range
349 if (!m_binnedhits->getBinTool().inRange(m_truthparset)) {
350 ATH_MSG_INFO("Truth out of range because truth parset = " << m_truthparset << " wrt min = " << m_binnedhits->getBinTool().parMin() << ", max = " << m_binnedhits->getBinTool().parMax());
351 return;
352 }
353
354 // Check that truth track falls in an actual bin
355 // this should alway pass, except for weird events
356 m_truthIsValid = true;
357 for (auto &step : m_binnedhits->getBinTool().steps()) {
358 if (!step->validBinsFull()[m_truthbin[step->stepNum()]]) {
359 ATH_MSG_INFO("Truth Bin not valid! Step " << step->stepName() << " "
360 << m_truthbin[step->stepNum()]
361 << " : " << m_truthpars);
362 std::vector<FPGATrackSimBinUtil::IdxSet> idxsets =
364 std::vector<unsigned>({0, 1, 2, 3, 4}),
365 m_truthbin[step->stepNum()]);
366 for (FPGATrackSimBinUtil::IdxSet &idxset : idxsets) {
367 ATH_MSG_INFO("Truth Box "
368 << bindesc->parSetToTrackPars(step->binLowEdge(idxset)));
369 }
370 m_truthIsValid = false;
371 }
372 }
373}
374
375
377{
379
380 // this finds the parameters at all 2^5 corners of the bin and then finds the min and max of those
381 std::vector<FPGATrackSimBinUtil::IdxSet> idxsets = FPGATrackSimBinUtil::makeVariationSet(std::vector<unsigned>({0,1,2,3,4}),idx);
382 const FPGATrackSimBinTool &bintool = m_binnedhits->getBinTool();
383 const IFPGATrackSimBinDesc* bindesc = bintool.binDesc();
384
385 // get window in std parameters for bin
386 FPGATrackSimTrackPars minpars = bindesc->parSetToTrackPars(bintool.lastStep()->binCenter(idx));
387 FPGATrackSimTrackPars maxpars = bindesc->parSetToTrackPars(bintool.lastStep()->binCenter(idx));
388 for (FPGATrackSimBinUtil::IdxSet & idxset : idxsets) {
389 FPGATrackSimTrackPars trackpars = bindesc->parSetToTrackPars(bintool.lastStep()->binLowEdge(idxset));
390 for (unsigned par =0; par < FPGATrackSimTrackPars::NPARS; par++) {
391 minpars[par] = std::min(minpars[par],trackpars[par]);
392 maxpars[par] = std::max(maxpars[par],trackpars[par]);
393 }
394 }
395
396 // check if truth track is in bin within padding
397 FPGATrackSimTrackPars padding;
402 padding[FPGATrackSimTrackPars::IHIP] = 1000.0*m_qptpad;
403 bool inRange = true;
404 for (unsigned par =0; par < FPGATrackSimTrackPars::NPARS; par++) {
405 inRange = inRange && (m_truthpars[par] > minpars[par]-padding[par]);
406 inRange = inRange && (m_truthpars[par] < maxpars[par]+padding[par]);
407 }
408 //m_binPlotsActive |= inRange;
410
411
412}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
Binning Utilities for GenScanTool.
Binning Classes for GenScanTool.
Structs that store the 5 track parameters.
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
Defines Parameters used for binning.
bool inRange(const double *boundaries, const double value, const double tolerance=0.02)
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
const std::vector< std::string > & stepNames() const
const IFPGATrackSimBinDesc * binDesc() const
const ToolHandleArray< FPGATrackSimBinStep > & steps() const
static double dPhiHitTrkFromPars(double r, const FPGATrackSimTrackPars &pars)
float getGPhi() const
float getZ() const
float getR() const
Gaudi::Property< double > m_z0pad
FPGATrackSimBinUtil::ParSet m_truthparset
StatusCode registerHistograms(const FPGATrackSimBinnedHits *binnedhits, bool skipTruth)
FPGATrackSimLayerStudyTool(const std::string &, const std::string &, const IInterface *)
Gaudi::Property< std::string > m_layerStudyTreeName
Gaudi::Property< std::string > m_truthTreeName
std::vector< FPGATrackSimBinUtil::IdxSet > m_truthbin
Gaudi::Property< double > m_etaScale
StatusCode makeAndRegHist(HistType *&ptr, HistDef... histargs)
virtual StatusCode initialize() override
Gaudi::Property< double > m_phiScale
const FPGATrackSimBinnedHits * m_binnedhits
Gaudi::Property< double > m_d0pad
Gaudi::Property< bool > m_plotAllBins
ServiceHandle< ITHistSvc > m_tHistSvc
Gaudi::Property< double > m_qptpad
Gaudi::Property< double > m_phipad
void fillHitLevelInput(const FPGATrackSimHit *hit)
StatusCode makeAndRegHistVector(std::vector< HistType * > &vec, unsigned len, const std::vector< std::string > *namevec, const char *namebase, HistDef... histargs)
Gaudi::Property< double > m_drScale
Gaudi::Property< double > m_etapad
Gaudi::Property< std::string > m_dir
std::vector< std::string > m_distPlotClasses
void setBinPlotsActive(const FPGATrackSimBinUtil::IdxSet &idx)
virtual double phiResidual(const FPGATrackSimBinUtil::ParSet &parset, FPGATrackSimHit const *hit) const =0
virtual double etaResidual(const FPGATrackSimBinUtil::ParSet &parset, FPGATrackSimHit const *hit) const =0
virtual const std::string & parNames(unsigned i) const =0
virtual const FPGATrackSimTrackPars parSetToTrackPars(const FPGATrackSimBinUtil::ParSet &parset) const =0
virtual const FPGATrackSimBinUtil::ParSet trackParsToParSet(const FPGATrackSimTrackPars &pars) const =0
std::vector< IdxSet > makeVariationSet(const std::vector< unsigned > &scanpars, const IdxSet &idx)
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.