ATLAS Offline Software
Loading...
Searching...
No Matches
FPGATrackSimLogicalHitsProcessAlg.cxx
Go to the documentation of this file.
1
2
3// Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
4
6
16
20
22
25
27
28#include "GaudiKernel/IEventProcessor.h"
29#include "AthenaKernel/Chrono.h"
30
31#include <algorithm>
32#include <vector>
33#include <optional>
34
35constexpr bool enableBenchmark =
36#ifdef BENCHMARK_FPGATRACKSIM
37 true;
38#else
39 false;
40#endif
41
43// Initialize
44
45FPGATrackSimLogicalHitsProcessAlg::FPGATrackSimLogicalHitsProcessAlg (const std::string& name, ISvcLocator* pSvcLocator) :
46 AthAlgorithm(name, pSvcLocator)
47{
48}
49
50
52{
53 // Dump the configuration to make sure it propagated through right
54 const std::vector<Gaudi::Details::PropertyBase*> props = this->getProperties();
55 for( Gaudi::Details::PropertyBase* prop : props ) {
56 if (prop->ownerTypeName()==this->type()) {
57 ATH_MSG_DEBUG("Property:\t" << prop->name() << "\t : \t" << prop->toString());
58 }
59 }
60
61 std::stringstream ss(m_description);
62 std::string line;
63 ATH_MSG_INFO("Tag config:");
64 if (!m_description.empty()) {
65 while (std::getline(ss, line, '\n')) {
66 ATH_MSG_INFO('\t' << line);
67 }
68 }
69 ATH_CHECK(m_roadFinderTool.retrieve());
70 ATH_CHECK(m_LRTRoadFilterTool.retrieve(EnableTool{m_doLRT}));
71 ATH_CHECK(m_LRTRoadFinderTool.retrieve(EnableTool{m_doLRT}));
72 ATH_CHECK(m_houghRootOutputTool.retrieve(EnableTool{m_doHoughRootOutput1st}));
73 ATH_CHECK(m_NNTrackTool.retrieve(EnableTool{m_doNNTrack}));
74 ATH_CHECK(m_roadFilterTool.retrieve(EnableTool{m_filterRoads}));
75 ATH_CHECK(m_roadFilterTool2.retrieve(EnableTool{m_filterRoads2}));
76
77 ATH_CHECK(m_spacepointsTool.retrieve(EnableTool{m_doSpacepoints}));
78
79 ATH_CHECK(m_trackFitterTool_1st.retrieve(EnableTool{m_doTracking}));
81 ATH_CHECK(m_writeOutputTool.retrieve());
84
85
99
100
101
102 ATH_MSG_DEBUG("initialize() Instantiating root objects");
103
104 // ROOT branches created for test vectors.
105 m_logicEventOutputHeader = m_writeOutputTool->addOutputBranch(m_outputBranch.value(), true);
106
108
109 // Updated slicing engine test vectors will have three streams.
113
114 // We also need a pre- and post- SP copy of the SPs.
116
117 // Connect the slicing tools accordingly. We probably no longer need to hook up the roadfinder here.
120
121 ATH_MSG_DEBUG("initialize() Setting branch");
122
123 if (!m_monTool.empty())
124 ATH_CHECK(m_monTool.retrieve());
125
126 ATH_CHECK( m_FPGASpacePointsKey.initialize() );
127 ATH_CHECK( m_FPGAHitFilteredKey.initialize() );
128 ATH_CHECK( m_FPGARoadKey.initialize() );
129 ATH_CHECK( m_FPGATrackKey.initialize() );
130 ATH_CHECK( m_FPGAHitKey.initialize() );
131 ATH_CHECK( m_FPGAHitKey_1st.initialize() );
132 ATH_CHECK( m_FPGAHitKey_2nd.initialize() );
133 ATH_CHECK( m_FPGATruthTrackKey.initialize() );
134 ATH_CHECK( m_FPGAOfflineTrackKey.initialize() );
135 ATH_CHECK( m_FPGAEventInfoKey.initialize() );
136
137 ATH_CHECK( m_chrono.retrieve() );
138 ATH_MSG_DEBUG("initialize() Finished");
139
140 return StatusCode::SUCCESS;
141}
142
143
145// MAIN EXECUTE ROUTINE //
147
149{
150 const EventContext& ctx = getContext();
151
152 // Get reference to hits from StoreGate.
154 if (!FPGAHits.isValid()) {
155 if (m_evt == 0) {
156 ATH_MSG_WARNING("Didn't receive " << FPGAHits.key() << " on first event; assuming no input events.");
157 }
158 SmartIF<IEventProcessor> appMgr{service("ApplicationMgr")};
159 if (!appMgr) {
160 ATH_MSG_ERROR("Failed to retrieve ApplicationMgr as IEventProcessor");
161 return StatusCode::FAILURE;
162 }
163 return appMgr->stopRun();
164 }
165
166 // Set up write handles.
170
171 // Use ConstDataVector with VIEW_ELEMENTS for non-owning const pointer storage
174 auto* FPGAHits_1st_cdv = FPGAHits_1st.ptr();
175 auto* FPGAHits_2nd_cdv = FPGAHits_2nd.ptr();
176
177 ATH_CHECK( FPGARoads_1st.record (std::make_unique<FPGATrackSimRoadCollection>()));
178
180 ATH_CHECK(FPGATracks_1stHandle.record (std::make_unique<FPGATrackSimTrackCollection>()));
181
183 ATH_CHECK( FPGAHitsFiltered_1st.record (std::make_unique<FPGATrackSimHitCollection>()));
184
186 ATH_CHECK( FPGASpacePoints.record (std::make_unique<FPGATrackSimClusterCollection>()));
187
188 // Query the event selection service to make sure this event passed cuts.
189 if (!m_evtSel->getSelectedEvent()) {
190
191 // Potentially write the output data, now it's empty and reset, but this keeps things synchronized over trees
192 if (m_writeOutputData) {
193 std::vector<FPGATrackSimRoad> roads_1st;
194 std::vector<FPGATrackSimTrack> tracks_1st;
195 auto dataFlowInfo = std::make_unique<FPGATrackSimDataFlowInfo>();
196 ATH_CHECK(writeOutputData(roads_1st, tracks_1st, dataFlowInfo.get()));
197 }
198
199 return StatusCode::SUCCESS;
200 }
201 ATH_MSG_INFO("Event accepted by: " << m_evtSel->name());
202 if ((m_writeRegion>=0)&&(m_writeRegion==m_evtSel->getRegionID())) {
203 m_writeOutputTool->activateEventOutput();
204 }
205
206 // Event passes cuts, count it. technically, DataPrep does this now.
207 m_evt++;
208 // Read event info structure. all we need this for is to propagate to our event info structures.
210 if (!FPGAEventInfo.isValid()) {
211 ATH_MSG_ERROR("Could not find FPGA Event Info with key " << FPGAEventInfo.key());
212 return StatusCode::FAILURE;
213 }
214 FPGATrackSimEventInfo eventInfo = *FPGAEventInfo.cptr();
215 m_slicedFirstPixelHeader->newEvent(eventInfo);
216 m_slicedSecondPixelHeader->newEvent(eventInfo);
217 m_slicedStripHeader->newEvent(eventInfo);
218 m_slicedStripHeaderPreSP->newEvent(eventInfo);
219
220 std::vector<std::shared_ptr<const FPGATrackSimHit>> phits_output, phits_all, phits_1st, phits_2nd;
221 std::vector<const FPGATrackSimHit*> phits_strips; // this should store pointers to strip hits for this region
222
223 {
224 std::optional<Athena::Chrono> chronoSplitHits;
225 if constexpr (enableBenchmark) chronoSplitHits.emplace("1st Stage: Split hits to 1st and 2nd stage", m_chrono.get());
226
227 phits_1st.reserve(FPGAHits->size());
228 phits_2nd.reserve(FPGAHits->size());
229 ATH_MSG_DEBUG("Incoming Hits: " << FPGAHits->size());
230 auto noDelete = [](const FPGATrackSimHit*) {};
231 for (const FPGATrackSimHit* hit : *(FPGAHits.cptr())) {
232 //vectors are non-owning due to no-op deleter.
233 //should use some mechanism other than shared_ptr here (std::reference_wrapper? bare pointer?)
234 auto sharedHit = std::shared_ptr<const FPGATrackSimHit>{hit, noDelete};
235 phits_all.push_back(sharedHit);
236 if(m_noHitFilter) {
237 phits_1st.push_back(sharedHit);
238 phits_2nd.push_back(std::move(sharedHit));
239 if(hit->isStrip()) phits_strips.push_back(hit);
240 }
241 }
242
243 // Use the slicing engine tool to do the stage-based separation. Does not use the pmap.
244 if(!m_noHitFilter) m_slicingEngineTool->sliceHits(phits_all, phits_1st, phits_2nd, phits_strips);
245 }
246
247 // record 1st stage hits in SG (VIEW_ELEMENTS - no copy, just store pointers)
248 for (auto& hit : phits_1st) {
249 FPGAHits_1st_cdv->push_back(hit.get());
250 }
251
253 // The slicing engine puts strip hits into a logical event input header. That header now needs to go
254 // to the spacepoint tool if it's turned on. Those hits then get added to phits_1st or phits_2nd as appropriate.
255 if (m_doSpacepoints) {
256 std::vector<FPGATrackSimCluster> spacepoints;
257 std::optional<Athena::Chrono> chronoSPFormation;
258 if constexpr (enableBenchmark) chronoSPFormation.emplace("1st Stage: SP formation", m_chrono.get());
259 ATH_CHECK(m_spacepointsTool->DoSpacePoints(*m_slicedStripHeader, spacepoints));
260 // Move spacepoints into the output container to avoid unnecessary copies
261 for (FPGATrackSimCluster& cluster : spacepoints) {
262 FPGASpacePoints->push_back(std::move(cluster));
263 }
264
265 // Add spacepoint hits to appropriate stage (using FPGASpacePoints directly from StoreGate)
266 for (const auto& cluster : *FPGASpacePoints) {
267 // Keep the exact constituent hits of the spacepoint (not just the cluster-equivalent summary)
268 for (const auto& hit : cluster.getHitList()) {
269 (m_secondStageStrips ? phits_2nd : phits_1st).emplace_back(&hit, [](const FPGATrackSimHit*){});
270 }
271 }
272 } else {
273 // If spacepoints are disabled, add strip hits from phits_strips (filled by slicing engine)
274 // These pointers point to hits in FPGAHits, which has stable lifetime in StoreGate
275 for (const FPGATrackSimHit* hit : phits_strips) {
276 (m_secondStageStrips ? phits_2nd : phits_1st).emplace_back(hit, [](const FPGATrackSimHit*){});
277 }
278 }
279
280 // VIEW_ELEMENTS - no copy, just store pointers
281 for (auto& hit : phits_2nd) {
282 FPGAHits_2nd_cdv->push_back(hit.get());
283 }
284
285 // Add all hits including SPs to this for the HoughRootOutputTool
286 for (const FPGATrackSimHit* hit : *(FPGAHits_2nd.cptr())) {
287 phits_output.emplace_back(hit, [](const FPGATrackSimHit*){});
288 }
289 ATH_MSG_DEBUG("1st stage hits: " << phits_1st.size() << " 2nd stage hits: " << phits_2nd.size() );
290 if (phits_1st.empty()) {
291 // Potentially write the output data, now it's empty and reset, but this keeps things synchronized over trees
292 if (m_writeOutputData) {
293 std::vector<FPGATrackSimRoad> roads_1st;
294 std::vector<FPGATrackSimTrack> tracks_1st;
295 auto dataFlowInfo = std::make_unique<FPGATrackSimDataFlowInfo>();
296 ATH_CHECK(writeOutputData(roads_1st, tracks_1st, dataFlowInfo.get()));
297 }
298 return StatusCode::SUCCESS;
299 }
300
301 // Get truth tracks from DataPrep as well.
303 if (!FPGATruthTracks.isValid()) {
304 ATH_MSG_ERROR("Could not find FPGA Truth Track Collection with key " << FPGATruthTracks.key());
305 return StatusCode::FAILURE;
306 }
307 // Same for offline tracks.
309 if (!FPGAOfflineTracks.isValid()) {
310 ATH_MSG_ERROR("Could not find FPGA Offline Track Collection with key " << FPGAOfflineTracks.key());
311 return StatusCode::FAILURE;
312 }
313
314
316 // roads //
318
320 const std::vector<FPGATrackSimTruthTrack>& truthtracks = *FPGATruthTracks;
322 auto nLogicalLayers = m_FPGATrackSimMapping->PlaneMap_1st(0)->getNLogiLayers();
325 auto monitorRoads = [&](auto& monitor, const auto& roads) {
326 if (!monitor.empty()) {
327 monitor->fillRoad(roads, truthtracks, nLogicalLayers);
328 }
329 };
330
331 std::vector<FPGATrackSimRoad> roads_1st;
332 {
333 std::optional<Athena::Chrono> chronoGetRoads;
334 if constexpr (enableBenchmark) chronoGetRoads.emplace("1st Stage: GetRoads", m_chrono.get());
335 // get roads
336 ATH_CHECK(m_roadFinderTool->getRoads(phits_1st, roads_1st, *(FPGATruthTracks.cptr())));
337 monitorRoads(m_1st_stage_road_monitor, roads_1st);
338 }
339
340
341 {
342 // Standard road Filter
343 std::optional<Athena::Chrono> chronoRoadFiltering;
344 if constexpr (enableBenchmark) chronoRoadFiltering.emplace("1st Stage: RoadFiltering", m_chrono.get());
345 std::vector<FPGATrackSimRoad> postfilter_roads;
346 if (m_filterRoads) {
347 ATH_CHECK(m_roadFilterTool->filterRoads(roads_1st, postfilter_roads));
348 roads_1st = std::move(postfilter_roads);
349 }
351 monitorRoads(m_1st_stage_road_post_filter_1_monitor, roads_1st);
352 }
353
354
355 {
356 // overlap removal
357 std::optional<Athena::Chrono> chronoOverlapRemoval;
358 if constexpr (enableBenchmark) chronoOverlapRemoval.emplace("1st Stage: OverlapRemoval", m_chrono.get());
359 if (m_doOverlapRemoval) ATH_CHECK(m_overlapRemovalTool_1st->runOverlapRemoval(roads_1st));
361 monitorRoads(m_1st_stage_road_post_OLR_monitor, roads_1st);
362 }
363
364
365 {
366 // Road Filter2
367 std::optional<Athena::Chrono> chronoRoadFiltering2;
368 if constexpr (enableBenchmark) chronoRoadFiltering2.emplace("1st Stage: RoadFiltering2", m_chrono.get());
369 std::vector<FPGATrackSimRoad> postfilter2_roads;
370 if (m_filterRoads2) {
371 ATH_CHECK(m_roadFilterTool2->filterRoads(roads_1st, postfilter2_roads));
372 roads_1st = std::move(postfilter2_roads);
373 }
375 monitorRoads(m_1st_stage_road_post_filter_2_monitor, roads_1st);
376 }
377
379 // tracks //
381
383 auto monitorTracks = [&](auto& monitor, const auto& tracks) {
384 if (monitor.empty()) return;
385 // prepare vector<const FPGATrackSimTrack*> regardless of input type
386 std::vector<const FPGATrackSimTrack*> track_ptrs;
387 track_ptrs.reserve(tracks.size());
388 // transform tracks into a vector of pointers
389 if constexpr (std::is_pointer_v<typename std::decay_t<decltype(tracks)>::value_type>) {
390 // tracks is std::vector<const FPGATrackSimTrack*>
391 track_ptrs.insert(track_ptrs.end(), tracks.begin(), tracks.end());
392 } else {
393 // tracks is std::vector<FPGATrackSimTrack>
394 std::transform(tracks.begin(), tracks.end(), std::back_inserter(track_ptrs), [](const auto& t) { return &t; });
395 }
396 // monitor using track pointers
397 monitor->fillTrack(track_ptrs, truthtracks, 1.e15);
398 };
399
400 std::vector<FPGATrackSimTrack> tracks_1st;
401 {
402 // Get tracks
403 std::optional<Athena::Chrono> chronoGettingTracks;
404 if constexpr (enableBenchmark) chronoGettingTracks.emplace("1st Stage: Getting Tracks", m_chrono.get());
405 if (m_doTracking) {
406 if (m_doNNTrack) {
407 ATH_MSG_DEBUG("Performing NN tracking");
408 ATH_CHECK(m_NNTrackTool->getTracks_1st(roads_1st, tracks_1st));
409 if (m_doGNNTrack) {
410 ATH_MSG_DEBUG("Performing track parameter estimation");
411 ATH_CHECK(m_NNTrackTool->setTrackParameters(tracks_1st,true,m_evtSel->getMin(), m_evtSel->getMax()));
412 }
413 } else {
414 ATH_MSG_DEBUG("Performing Linear tracking");
415 if (m_passLowestChi2TrackOnly) { // Pass only the lowest chi2 track per road
416 // Loop over roads and keep only the best track for each road
417 for (const auto& road : roads_1st) {
418 std::vector<FPGATrackSimTrack> tracksForCurrentRoad;
419
420 // Collect tracks for this road
421 std::vector<FPGATrackSimRoad> roadVec = {road};
422 ATH_CHECK(m_trackFitterTool_1st->getTracks(roadVec, tracksForCurrentRoad, m_evtSel->getMin(), m_evtSel->getMax()));
423
424 // Find the best track for this road
425 if (!tracksForCurrentRoad.empty()) {
426 auto bestTrackIter = std::min_element(
427 tracksForCurrentRoad.begin(), tracksForCurrentRoad.end(),
428 [](const FPGATrackSimTrack& a, const FPGATrackSimTrack& b) {
429 return a.getChi2ndof() < b.getChi2ndof();
430 });
431
432 if (bestTrackIter != tracksForCurrentRoad.end() && bestTrackIter->getChi2ndof() < 1.e15) {
433 tracks_1st.push_back(*bestTrackIter);
434 }
435 }
436 }
437 } else { // Pass all tracks with chi2 < 1e15
438 ATH_CHECK(m_trackFitterTool_1st->getTracks(roads_1st, tracks_1st, m_evtSel->getMin(), m_evtSel->getMax()));
439 }
440 }
441 } else { // No tracking;
442 ATH_MSG_DEBUG("No tracking. Just running dummy road2track algorith");
443 if(m_doGNNPixelSeeding) { //For GNNPixelSeeding, convert the roads to a track in the simplest form
444 for (const auto& road : roads_1st) {
445 std::vector<std::shared_ptr<const FPGATrackSimHit>> track_hits;
446 for (unsigned layer = 0; layer < road.getNLayers(); ++layer) {
447 track_hits.insert(track_hits.end(), road.getHitPtrs(layer).begin(), road.getHitPtrs(layer).end());
448 }
449
450 FPGATrackSimTrack track_cand;
451 track_cand.setNLayers(track_hits.size());
452 for (size_t ihit = 0; ihit < track_hits.size(); ++ihit) {
453 track_cand.setFPGATrackSimHit(ihit, track_hits[ihit]);
454 }
455 tracks_1st.push_back(std::move(track_cand));
456 }
457 }
458 else { roadsToTrack(roads_1st, tracks_1st, m_FPGATrackSimMapping->PlaneMap_1st(0)); }
459 }
460
461 // calculateTruth() before any monitors
462 // this explicitly calculates barcode, barcodeFrac and eventIndex
463 ATH_MSG_DEBUG("doMultiTruth = " << m_doMultiTruth);
464 if (m_doMultiTruth)
465 for (auto &track : tracks_1st)
466 track.calculateTruth();
467
470 monitorTracks(m_1st_stage_track_monitor, tracks_1st);
471 }
472
473
474 {
475 // set track parameters to truth
476 std::optional<Athena::Chrono> chronoSetTruthParams;
477 if constexpr (enableBenchmark) chronoSetTruthParams.emplace("1st Stage: Set Track Parameters to Truth", m_chrono.get());
478 //Loop over tracks and set the region for all of them, also optionally set track parameters to truth
479 for (FPGATrackSimTrack& track : tracks_1st) {
480 track.setRegion(m_region);
481 if (m_SetTruthParametersForTracks >= 0 && truthtracks.size() > 0) {
483 track.setQOverPt(truthtracks.front().getQOverPt());
484 else if (m_SetTruthParametersForTracks != 1)
485 track.setD0(truthtracks.front().getD0());
486 else if (m_SetTruthParametersForTracks != 2)
487 track.setPhi(truthtracks.front().getPhi());
488 else if (m_SetTruthParametersForTracks != 3)
489 track.setZ0(truthtracks.front().getZ0());
490 else if (m_SetTruthParametersForTracks != 4)
491 track.setEta(truthtracks.front().getEta());
492 }
493 }
496 monitorTracks(m_1st_stage_track_post_setTruth_monitor, tracks_1st);
497 }
498
499 // Loop over roads and store them in SG (after track finding to also copy the sector information)
500 for (auto const& road : roads_1st) {
501 FPGARoads_1st->push_back(road);
502 }
503
504 // Do some simple monitoring of efficiencies for truth before anything else
505 if (truthtracks.size() > 0) {
506 m_evt_truth++;
507 if (roads_1st.size() > 0) m_nRoadsFound++;
508 if (roads_1st.size() > m_maxNRoadsFound) m_maxNRoadsFound = roads_1st.size();
509 if (tracks_1st.size() > 0) {
511 if (tracks_1st.size() > m_maxNTracksTot) m_maxNTracksTot = tracks_1st.size();
512 }
513 }
514
515
516 // Apply OLR but remove tracks that failed chi2 first
517 for (auto itrack = tracks_1st.begin(); itrack != tracks_1st.end();) {
518 if (!passesChi2Cut(*itrack)) itrack = tracks_1st.erase(itrack);
519 else ++itrack;
520 }
521 // do monitoring of chi2
522 m_nTracksChi2Tot += tracks_1st.size();
524 monitorTracks(m_1st_stage_track_post_chi2_monitor, tracks_1st);
525
526 {
527 // overlap removal
528 std::optional<Athena::Chrono> chronoOverlapRemoval2;
529 if constexpr (enableBenchmark) chronoOverlapRemoval2.emplace("1st Stage: OverlapRemoval", m_chrono.get());
530 if (m_doOverlapRemoval) ATH_CHECK(m_overlapRemovalTool_1st->runOverlapRemoval(tracks_1st));
531 // monitor variables (vectors of pointers)
532 std::vector<const FPGATrackSimTrack*> tracks_1st_after_chi2;
533 std::vector<const FPGATrackSimTrack*> tracks_1st_after_overlap;
534 for (const FPGATrackSimTrack& track : tracks_1st) {
535 if (track.passedOR()) {
536 tracks_1st_after_overlap.push_back(&track);
538 }
539 }
541 monitorTracks(m_1st_stage_track_post_OLR_monitor, tracks_1st_after_overlap);
542 }
543
544 m_nRoadsTot += roads_1st.size();
545 m_nTracksTot += tracks_1st.size();
546 // Do some simple monitoring of efficiencies now for tracks passing chi2 and potentially OLR
547 if (truthtracks.size() > 0) {
548
549 unsigned npasschi2(0);
550 unsigned npasschi2OLR(0);
551 if (tracks_1st.size() > 0) {
552 for (const auto& track : tracks_1st) { // these passed the chi2
553 npasschi2++;
554 if (track.passedOR()) {
555 npasschi2OLR++;
556 }
557 }
558 }
559 if (npasschi2 > m_maxNTracksChi2Tot) m_maxNTracksChi2Tot = npasschi2;
560 if (npasschi2OLR > m_maxNTracksChi2OLRTot) m_maxNTracksChi2OLRTot = npasschi2OLR;
561 if (npasschi2 > 0) m_nTracksChi2Found++;
562 if (npasschi2OLR > 0) m_nTracksChi2OLRFound++;
563 }
564
565 // Now pick hits for seeding, this changes the tracks to have fewer hits
566 if (m_keepHitsStrategy > 0) MakeSeedTracks(tracks_1st);
567
568 for (const FPGATrackSimTrack& track : tracks_1st) {
569 FPGATracks_1stHandle->push_back(track);
570 }
571
572 // Now, we may want to do large-radius tracking on the hits not used by the first stage tracking.
573 // This follows overlap removal.
574 std::vector<FPGATrackSimRoad> roadsLRT;
575 std::vector<FPGATrackSimTrack> tracksLRT; // currently empty
576 if (m_doLRT) {
577 // Filter out hits that are on successful first-stage tracks
578 std::vector<std::shared_ptr<const FPGATrackSimHit>> remainingHits;
579
581 ATH_MSG_DEBUG("Doing hit filtering based on prompt tracks.");
582 ATH_CHECK(m_LRTRoadFilterTool->filterUsedHits(tracks_1st, phits_1st, remainingHits));
583
584 for (const auto &Hit : remainingHits) FPGAHitsFiltered_1st->push_back(new FPGATrackSimHit(*Hit));
585
586 } else {
587 ATH_MSG_DEBUG("No hit filtering requested; using all hits for LRT.");
588 remainingHits = std::move(phits_1st);
589 }
590
591 // Get LRT roads with remaining hits
592 ATH_MSG_DEBUG("Finding LRT roads");
593 ATH_CHECK(m_LRTRoadFinderTool->getRoads( remainingHits, roadsLRT ));
594 }
595
596 auto dataFlowInfo = std::make_unique<FPGATrackSimDataFlowInfo>();
597
598 // Write the output and reset
599 if (m_writeOutputData) {
600 ATH_CHECK(writeOutputData(roads_1st, tracks_1st, dataFlowInfo.get()));
601 }
602
603 // This one we can do-- by passing in truth and offline tracks via storegate above (*FPGAOfflineTracks).
605 ATH_MSG_DEBUG("Running HoughRootOutputTool in 1st stage.");
606
607 SmartIF<IEventProcessor> appMgr{service("ApplicationMgr")};
608 if (!appMgr) {
609 ATH_MSG_ERROR("Failed to retrieve ApplicationMgr as IEventProcessor");
610 return StatusCode::FAILURE;
611 }
612
613 // Create output ROOT file
614 ATH_CHECK(m_houghRootOutputTool->fillTree(tracks_1st, truthtracks, *FPGAOfflineTracks, phits_output, m_writeOutNonSPStripHits, false));
615 }
616
617 // Reset data pointers
620
621 return StatusCode::SUCCESS;
622}
623
624
626// INPUT PASSING, READING AND PROCESSING //
628
629StatusCode FPGATrackSimLogicalHitsProcessAlg::writeOutputData( const std::vector<FPGATrackSimRoad>& roads_1st,
630 std::vector<FPGATrackSimTrack> const& tracks_1st,
631 FPGATrackSimDataFlowInfo const* dataFlowInfo)
632{
634
635 ATH_MSG_DEBUG("NFPGATrackSimRoads_1st = " << roads_1st.size() << ", NFPGATrackSimTracks_1st = " << tracks_1st.size());
636
637 if (!m_writeOutputData) return StatusCode::SUCCESS;
638 m_logicEventOutputHeader->reserveFPGATrackSimRoads_1st(roads_1st.size());
639 m_logicEventOutputHeader->addFPGATrackSimRoads_1st(roads_1st);
640
641 m_logicEventOutputHeader->reserveFPGATrackSimTracks_1st(tracks_1st.size());
642 m_logicEventOutputHeader->addFPGATrackSimTracks_1st(tracks_1st);
643
644 m_logicEventOutputHeader->setDataFlowInfo(*dataFlowInfo);
645 ATH_MSG_DEBUG(m_logicEventOutputHeader->getDataFlowInfo());
646
647 // It would be nice to rearrange this so both algorithms use one instance of this tool, I think.
648 // Which means that dataprep can't call writeData because that does Fill().
649 ATH_CHECK(m_writeOutputTool->writeData());
650
651
652
653 return StatusCode::SUCCESS;
654}
655
656
658// Finalize
659
661{
662 ATH_MSG_INFO("PRINTING FPGATRACKSIM SIMPLE STATS");
663 ATH_MSG_INFO("========================================================================================");
664 ATH_MSG_INFO("Ran on events = " << m_evt);
665 ATH_MSG_INFO("Inclusive efficiency to find a road = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_nRoadsFound/(float)m_evt_truth)));
667 ATH_MSG_INFO("New Inclusive efficiency to find a road = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_1st_stage_road_monitor->getNElements()/(float)m_evt_truth)));
669 ATH_MSG_INFO("New Inclusive efficiency to find a road passing filter1 = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_1st_stage_road_post_filter_1_monitor->getNElements()/(float)m_evt_truth)));
671 ATH_MSG_INFO("New Inclusive efficiency to find a road passing OLR = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_1st_stage_road_post_OLR_monitor->getNElements()/(float)m_evt_truth)));
673 ATH_MSG_INFO("New Inclusive efficiency to find a road passing filter2 = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_1st_stage_road_post_filter_2_monitor->getNElements()/(float)m_evt_truth)));
674
676 ATH_MSG_INFO("Inclusive efficiency to find a track = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_nTracksFound/(float)m_evt_truth)));
677 ATH_MSG_INFO("New Inclusive efficiency to find a track = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_1st_stage_track_monitor->getNElements()/(float)m_evt_truth)));
679 ATH_MSG_INFO("New Inclusive efficiency to find a track after set truth= " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_1st_stage_track_post_setTruth_monitor->getNElements()/(float)m_evt_truth)));
681 ATH_MSG_INFO("Inclusive efficiency to find a track passing chi2 = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_nTracksChi2Found/(float)m_evt_truth)));
682 ATH_MSG_INFO("New Inclusive efficiency to find a track passing chi2 = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_1st_stage_track_post_chi2_monitor->getNElements()/(float)m_evt_truth)));
684 ATH_MSG_INFO("Inclusive efficiency to find a track passing chi2 and OLR = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_nTracksChi2OLRFound/(float)m_evt_truth)));
685 ATH_MSG_INFO("New Inclusive efficiency to find a track passing chi2 and OLR = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_1st_stage_track_post_OLR_monitor->getNElements()/(float)m_evt_truth)));
686
687
688 ATH_MSG_INFO("Number of 1st stage roads/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_nRoadsTot/(float)m_evt)));
690 ATH_MSG_INFO("New Number of 1st stage roads/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_1st_stage_road_monitor->getTotNElements()/(float)m_evt)));
692 ATH_MSG_INFO("New Number of 1st stage roads passing filter1/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_1st_stage_road_post_filter_1_monitor->getTotNElements()/(float)m_evt)));
694 ATH_MSG_INFO("New Number of 1st stage roads passing OLR/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_1st_stage_road_post_OLR_monitor->getTotNElements()/(float)m_evt)));
696 ATH_MSG_INFO("New Number of 1st stage roads passing filter2/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_1st_stage_road_post_filter_2_monitor->getTotNElements()/(float)m_evt)));
697
699 ATH_MSG_INFO("Number of 1st stage track combinations/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_nTracksTot/(float)m_evt)));
700 ATH_MSG_INFO("New Number of 1st stage track combinations/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_1st_stage_track_monitor->getTotNElements()/(float)m_evt)));
702 ATH_MSG_INFO("New Number of 1st stage track after set truth/event= " << (m_evt == 0 ? "NAN" : std::to_string(m_1st_stage_track_post_setTruth_monitor->getTotNElements()/(float)m_evt)));
704 ATH_MSG_INFO("Number of 1st stage tracks passing chi2/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_nTracksChi2Tot/(float)m_evt)));
705 ATH_MSG_INFO("New Number of 1st stage track passing chi2/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_1st_stage_track_post_chi2_monitor->getTotNElements()/(float)m_evt)));
707 ATH_MSG_INFO("Number of 1st stage tracks passing chi2 and OLR/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_nTracksChi2OLRTot/(float)m_evt)));
708 ATH_MSG_INFO("New Number of 1st stage track passing chi2 and OLR/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_1st_stage_track_post_OLR_monitor->getTotNElements()/(float)m_evt)));
709 ATH_MSG_INFO("========================================================================================");
710
711 ATH_MSG_INFO("Max number of 1st stage roads in an event = " << m_maxNRoadsFound);
713 ATH_MSG_INFO("New Max number of 1st stage roads in an event = " << m_1st_stage_road_monitor->getMaxNElements());
715 ATH_MSG_INFO("New Max number of 1st stage roads passing filter1 in an event = " << m_1st_stage_road_post_filter_1_monitor->getMaxNElements());
717 ATH_MSG_INFO("New Max number of 1st stage roads passing OLR in an event = " << m_1st_stage_road_post_OLR_monitor->getMaxNElements());
719 ATH_MSG_INFO("New Max number of 1st stage roads passing filter2 in an event = " << m_1st_stage_road_post_filter_2_monitor->getMaxNElements());
720
722 ATH_MSG_INFO("Max number of 1st stage track combinations in an event = " << m_maxNTracksTot);
723 ATH_MSG_INFO("New Max number of 1st stage track combinations in an event = " << m_1st_stage_track_monitor->getMaxNElements());
725 ATH_MSG_INFO("New Max number of 1st stage tracks after set truth in an event = " << m_1st_stage_track_post_setTruth_monitor->getMaxNElements());
727 ATH_MSG_INFO("Max number of 1st stage tracks passing chi2 in an event = " << m_maxNTracksChi2Tot);
728 ATH_MSG_INFO("New Max number of 1st stage tracks passing chi2 in an event = " << m_1st_stage_track_post_chi2_monitor->getMaxNElements());
730 ATH_MSG_INFO("Max number of 1st stage tracks passing chi2 and OLR in an event = " << m_maxNTracksChi2OLRTot);
731 ATH_MSG_INFO("New Max number of 1st stage tracks passing chi2 and OLR in an event = " << m_1st_stage_track_post_OLR_monitor->getMaxNElements());
732 ATH_MSG_INFO("========================================================================================");
733
734 return StatusCode::SUCCESS;
735}
736
737
739// Helpers
740
741void FPGATrackSimLogicalHitsProcessAlg::printHitSubregions(std::vector<FPGATrackSimHit> const & hits)
742{
743 ATH_MSG_WARNING("Hit regions:");
744 for (const auto& hit : hits)
745 {
746 std::vector<uint32_t> regions = m_FPGATrackSimMapping->SubRegionMap()->getRegions(hit);
747 std::stringstream ss;
748 for (auto r : regions)
749 ss << r << ",";
750 ATH_MSG_WARNING("\t[" << ss.str() << "]");
751 }
752}
753
754
755// Chi2 cut implementation
757 bool retv = track.getChi2ndof() < m_trackScoreCut.value();
758
759 if (int(track.getFPGATrackSimHitPtrs().size()) < track.getNHits())
760 ATH_MSG_FATAL("More hits than layers on track");
761
762 unsigned missedhits = track.getFPGATrackSimHitPtrs().size() - track.getNHits();
763 if ((missedhits>=m_track_Chi2PhiCut.value().size()) ||
764 (missedhits>=m_track_Chi2EtaCut.value().size())) {
765 ATH_MSG_ERROR("More missed hits than entries in Chi2 cut " <<missedhits << " " << m_track_Chi2PhiCut.value().size() << " " <<m_track_Chi2EtaCut.value().size()
766 << track.getFPGATrackSimHitPtrs().size() << " " << track.getNHits());
767 }
768
769 if (m_track_Chi2PhiCut.value().at(missedhits) > 0) {
770 retv &= track.getChi2Phi() < m_track_Chi2PhiCut.value().at(missedhits);
771 }
772 if (m_track_Chi2EtaCut.value().at(missedhits) > 0) {
773 retv &= track.getChi2Eta() < m_track_Chi2EtaCut.value().at(missedhits);
774 }
775
776
777 return retv;
778}
779
780void FPGATrackSimLogicalHitsProcessAlg::MakeSeedTracks(std::vector<FPGATrackSimTrack>& tracks)
781{
782 for (auto &track : tracks) {
783 const auto& hitptrs = track.getFPGATrackSimHitPtrs();
784 layer_bitmask_t hitmask = 0x0;
785 for (unsigned ihit = 0; ihit < hitptrs.size(); ihit++) { // can't just use hit mask directly from track because that is for coordinates
786 if (hitptrs[ihit] && hitptrs[ihit]->isReal()) hitmask |= (0x1 << ihit);
787 }
788 std::vector<unsigned> toUse = PickHitsToUse(hitmask);
789 track.setNLayers(hitptrs.size()); //clears old hits
790 for (unsigned lyrToUse : toUse) {
791 track.setFPGATrackSimHit(lyrToUse, hitptrs.at(lyrToUse));
792 }
793 }
794}
795
796
798{
799 std::vector<unsigned> toUse;
800 switch (m_keepHitsStrategy) {
801 case 1: // try and pick hits furthest apart, use only 3
802 {
803 if (hitmask == 0x1f) { // miss no hits
804 toUse = {0,2,4};
805 }
806 else if (hitmask == 0x1e) { // miss inner layer, ie layer 0
807 toUse = {1,3,4};
808 }
809 else if (hitmask == 0x1d) { // miss layer 1
810 toUse = {0,2,4};
811 }
812 else if (hitmask == 0x1b) { // miss layer 2
813 toUse = {0,3,4};
814 }
815 else if (hitmask == 0x17) { // miss layer 3
816 toUse = {0,2,4};
817 }
818 else if (hitmask == 0x0f) { // miss layer 4
819 toUse = {0,2,3};
820 }
821 }
822 break;
823 case 2: // pick inner hits, use only 3
824 {
825 if (hitmask == 0x1f) { // miss no hits
826 toUse = {0,1,2};
827 }
828 else if (hitmask == 0x1e) { // miss inner layer, ie layer 0
829 toUse = {1,2,3};
830 }
831 else if (hitmask == 0x1d) { // miss layer 1
832 toUse = {0,2,3};
833 }
834 else if (hitmask == 0x1b) { // miss layer 2
835 toUse = {0,1,3};
836 }
837 else if (hitmask == 0x17) { // miss layer 3
838 toUse = {0,1,2};
839 }
840 else if (hitmask == 0x0f) { // miss layer 4
841 toUse = {0,1,2};
842 }
843 }
844 break;
845 case 3: // pick outer hits, use only 3
846 {
847 if (hitmask == 0x1f) { // miss no hits
848 toUse = {2,3,4};
849 }
850 else if (hitmask == 0x1e) { // miss inner layer, ie layer 0
851 toUse = {2,3,4};
852 }
853 else if (hitmask == 0x1d) { // miss layer 1
854 toUse = {2,3,4};
855 }
856 else if (hitmask == 0x1b) { // miss layer 2
857 toUse = {1,3,4};
858 }
859 else if (hitmask == 0x17) { // miss layer 3
860 toUse = {1,2,4};
861 }
862 else if (hitmask == 0x0f) { // miss layer 4
863 toUse = {1,2,3};
864 }
865 }
866 break;
867 case 4: // keep 4 hits, choose middle one to drop if necessary
868 {
869 if (hitmask == 0x1f) { // miss no hits
870 toUse = {0,1,2,3};
871 }
872 else if (hitmask == 0x1e) { // miss inner layer, ie layer 0
873 toUse = {1,2,3,4};
874 }
875 else if (hitmask == 0x1d) { // miss layer 1
876 toUse = {0,2,3,4};
877 }
878 else if (hitmask == 0x1b) { // miss layer 2
879 toUse = {0,1,3,4};
880 }
881 else if (hitmask == 0x17) { // miss layer 3
882 toUse = {0,1,2,4};
883 }
884 else if (hitmask == 0x0f) { // miss layer 4
885 toUse = {0,1,2,3};
886 }
887 }
888 break;
889 }
890 return toUse;
891}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Exception-safe IChronoSvc caller.
Structs that store the data flow information per event.
: FPGATrackSim-specific class to represent an hit in the detector.
void roadsToTrack(std::vector< FPGATrackSimRoad > &roads, std::vector< FPGATrackSimTrack > &track_cands, const FPGATrackSimPlaneMap *pmap)
Utilize NN score to build track candidates.
Overlap removal tool for FPGATrackSimTrack.
Maps ITK module indices to FPGATrackSim regions.
Stores slice definitions for FPGATrackSim regions.
Defines a class for roads.
Structs that store the 5 track parameters.
uint32_t layer_bitmask_t
static Double_t a
static Double_t ss
static const std::vector< std::string > regions
const EventContext & getContext() const
Deprecated methods (use the ones with EventContext).
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor with parameters:
DataVector adapter that acts like it holds const pointers.
ToolHandle< FPGATrackSimTrackMonitor > m_1st_stage_road_monitor
Gaudi::Property< std::string > m_sliceSecondPixelBranch
FPGATrackSimLogicalEventInputHeader * m_slicedHitHeader
ToolHandle< FPGATrackSimSpacePointsToolI > m_spacepointsTool
ToolHandle< FPGATrackSimOverlapRemovalTool > m_overlapRemovalTool_1st
ToolHandle< GenericMonitoringTool > m_monTool
ToolHandle< FPGATrackSimTrackMonitor > m_1st_stage_road_post_OLR_monitor
ToolHandle< FPGATrackSimSlicingEngineTool > m_slicingEngineTool
Gaudi::Property< std::string > m_sliceStripBranchPreSP
FPGATrackSimLogicalEventInputHeader * m_slicedStripHeaderPreSP
SG::WriteHandleKey< ConstDataVector< FPGATrackSimHitCollection > > m_FPGAHitKey_1st
ToolHandle< FPGATrackSimHoughRootOutputTool > m_houghRootOutputTool
ToolHandle< FPGATrackSimTrackMonitor > m_1st_stage_road_post_filter_2_monitor
void MakeSeedTracks(std::vector< FPGATrackSimTrack > &tracks)
FPGATrackSimLogicalEventInputHeader * m_slicedFirstPixelHeader
std::vector< unsigned > PickHitsToUse(layer_bitmask_t) const
ToolHandle< IFPGATrackSimRoadFilterTool > m_roadFilterTool
FPGATrackSimLogicalEventInputHeader * m_slicedSecondPixelHeader
SG::WriteHandleKey< FPGATrackSimRoadCollection > m_FPGARoadKey
ToolHandle< FPGATrackSimNNTrackTool > m_NNTrackTool
ToolHandle< FPGATrackSimLLPRoadFilterTool > m_LRTRoadFilterTool
bool passesChi2Cut(const FPGATrackSimTrack &track)
ToolHandle< IFPGATrackSimRoadFinderTool > m_LRTRoadFinderTool
ToolHandle< FPGATrackSimTrackMonitor > m_1st_stage_track_post_OLR_monitor
ToolHandle< FPGATrackSimOutputHeaderTool > m_writeOutputTool
ToolHandle< FPGATrackSimTrackMonitor > m_1st_stage_track_post_setTruth_monitor
SG::ReadHandleKey< FPGATrackSimHitCollection > m_FPGAHitKey
Gaudi::Property< std::string > m_sliceFirstPixelBranch
ToolHandle< FPGATrackSimTrackFitterTool > m_trackFitterTool_1st
ToolHandle< IFPGATrackSimRoadFilterTool > m_roadFilterTool2
ToolHandle< FPGATrackSimTrackMonitor > m_1st_stage_track_post_chi2_monitor
ToolHandle< FPGATrackSimTrackMonitor > m_1st_stage_track_monitor
StatusCode writeOutputData(const std::vector< FPGATrackSimRoad > &roads_1st, std::vector< FPGATrackSimTrack > const &tracks_1st, FPGATrackSimDataFlowInfo const *dataFlowInfo)
FPGATrackSimLogicalEventOutputHeader * m_logicEventOutputHeader
SG::WriteHandleKey< FPGATrackSimClusterCollection > m_FPGASpacePointsKey
SG::WriteHandleKey< ConstDataVector< FPGATrackSimHitCollection > > m_FPGAHitKey_2nd
ToolHandle< FPGATrackSimTrackMonitor > m_1st_stage_road_post_filter_1_monitor
virtual StatusCode execute() override
Execute method without EventContext (deprecated).
Gaudi::Property< std::vector< float > > m_track_Chi2PhiCut
SG::ReadHandleKey< FPGATrackSimOfflineTrackCollection > m_FPGAOfflineTrackKey
Gaudi::Property< std::vector< float > > m_track_Chi2EtaCut
ServiceHandle< IFPGATrackSimMappingSvc > m_FPGATrackSimMapping
ToolHandle< FPGATrackSimRoadUnionTool > m_roadFinderTool
void printHitSubregions(std::vector< FPGATrackSimHit > const &hits)
SG::WriteHandleKey< FPGATrackSimTrackCollection > m_FPGATrackKey
ServiceHandle< IFPGATrackSimEventSelectionSvc > m_evtSel
FPGATrackSimLogicalHitsProcessAlg(const std::string &name, ISvcLocator *pSvcLocator)
SG::WriteHandleKey< FPGATrackSimHitCollection > m_FPGAHitFilteredKey
SG::ReadHandleKey< FPGATrackSimTruthTrackCollection > m_FPGATruthTrackKey
SG::ReadHandleKey< FPGATrackSimEventInfo > m_FPGAEventInfoKey
FPGATrackSimLogicalEventInputHeader * m_slicedStripHeader
void setFPGATrackSimHit(unsigned i, std::shared_ptr< const FPGATrackSimHit > hit)
void setNLayers(int)
set the number of layers in the track.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
virtual const std::string & key() const override final
Return the StoreGate ID for the referenced object.
const_pointer_type cptr() const
Dereference the pointer.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
int r
Definition globals.cxx:22
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
constexpr bool enableBenchmark