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
148StatusCode FPGATrackSimLogicalHitsProcessAlg::execute(const EventContext& ctx)
149{
150
151 // Get reference to hits from StoreGate.
153 if (!FPGAHits.isValid()) {
154 if (m_evt == 0) {
155 ATH_MSG_WARNING("Didn't receive " << FPGAHits.key() << " on first event; assuming no input events.");
156 }
157 SmartIF<IEventProcessor> appMgr{service("ApplicationMgr")};
158 if (!appMgr) {
159 ATH_MSG_ERROR("Failed to retrieve ApplicationMgr as IEventProcessor");
160 return StatusCode::FAILURE;
161 }
162 return appMgr->stopRun();
163 }
164
165 // Set up write handles.
169
170 // Use ConstDataVector with VIEW_ELEMENTS for non-owning const pointer storage
173 auto* FPGAHits_1st_cdv = FPGAHits_1st.ptr();
174 auto* FPGAHits_2nd_cdv = FPGAHits_2nd.ptr();
175
176 ATH_CHECK( FPGARoads_1st.record (std::make_unique<FPGATrackSimRoadCollection>()));
177
179 ATH_CHECK(FPGATracks_1stHandle.record (std::make_unique<FPGATrackSimTrackCollection>()));
180
182 ATH_CHECK( FPGAHitsFiltered_1st.record (std::make_unique<FPGATrackSimHitCollection>()));
183
185 ATH_CHECK( FPGASpacePoints.record (std::make_unique<FPGATrackSimClusterCollection>()));
186
187 // Query the event selection service to make sure this event passed cuts.
188 if (!m_evtSel->getSelectedEvent()) {
189
190 // Potentially write the output data, now it's empty and reset, but this keeps things synchronized over trees
191 if (m_writeOutputData) {
192 std::vector<FPGATrackSimRoad> roads_1st;
193 std::vector<FPGATrackSimTrack> tracks_1st;
194 auto dataFlowInfo = std::make_unique<FPGATrackSimDataFlowInfo>();
195 ATH_CHECK(writeOutputData(roads_1st, tracks_1st, dataFlowInfo.get()));
196 }
197
198 return StatusCode::SUCCESS;
199 }
200 ATH_MSG_INFO("Event accepted by: " << m_evtSel->name());
201 if ((m_writeRegion>=0)&&(m_writeRegion==m_evtSel->getRegionID())) {
202 m_writeOutputTool->activateEventOutput();
203 }
204
205 // Event passes cuts, count it. technically, DataPrep does this now.
206 m_evt++;
207 // Read event info structure. all we need this for is to propagate to our event info structures.
209 if (!FPGAEventInfo.isValid()) {
210 ATH_MSG_ERROR("Could not find FPGA Event Info with key " << FPGAEventInfo.key());
211 return StatusCode::FAILURE;
212 }
213 FPGATrackSimEventInfo eventInfo = *FPGAEventInfo.cptr();
214 m_slicedFirstPixelHeader->newEvent(eventInfo);
215 m_slicedSecondPixelHeader->newEvent(eventInfo);
216 m_slicedStripHeader->newEvent(eventInfo);
217 m_slicedStripHeaderPreSP->newEvent(eventInfo);
218
219 std::vector<std::shared_ptr<const FPGATrackSimHit>> phits_output, phits_all, phits_1st, phits_2nd;
220 std::vector<const FPGATrackSimHit*> phits_strips; // this should store pointers to strip hits for this region
221
222 {
223 std::optional<Athena::Chrono> chronoSplitHits;
224 if constexpr (enableBenchmark) chronoSplitHits.emplace("1st Stage: Split hits to 1st and 2nd stage", m_chrono.get());
225
226 phits_1st.reserve(FPGAHits->size());
227 phits_2nd.reserve(FPGAHits->size());
228 ATH_MSG_DEBUG("Incoming Hits: " << FPGAHits->size());
229 auto noDelete = [](const FPGATrackSimHit*) {};
230 for (const FPGATrackSimHit* hit : *(FPGAHits.cptr())) {
231 //vectors are non-owning due to no-op deleter.
232 //should use some mechanism other than shared_ptr here (std::reference_wrapper? bare pointer?)
233 auto sharedHit = std::shared_ptr<const FPGATrackSimHit>{hit, noDelete};
234 phits_all.push_back(sharedHit);
235 if(m_noHitFilter) {
236 phits_1st.push_back(sharedHit);
237 phits_2nd.push_back(std::move(sharedHit));
238 if(hit->isStrip()) phits_strips.push_back(hit);
239 }
240 }
241
242 // Use the slicing engine tool to do the stage-based separation. Does not use the pmap.
243 if(!m_noHitFilter) m_slicingEngineTool->sliceHits(phits_all, phits_1st, phits_2nd, phits_strips);
244 }
245
246 // record 1st stage hits in SG (VIEW_ELEMENTS - no copy, just store pointers)
247 for (auto& hit : phits_1st) {
248 FPGAHits_1st_cdv->push_back(hit.get());
249 }
250
252 // The slicing engine puts strip hits into a logical event input header. That header now needs to go
253 // to the spacepoint tool if it's turned on. Those hits then get added to phits_1st or phits_2nd as appropriate.
254 if (m_doSpacepoints) {
255 std::vector<FPGATrackSimCluster> spacepoints;
256 std::optional<Athena::Chrono> chronoSPFormation;
257 if constexpr (enableBenchmark) chronoSPFormation.emplace("1st Stage: SP formation", m_chrono.get());
258 ATH_CHECK(m_spacepointsTool->DoSpacePoints(*m_slicedStripHeader, spacepoints));
259 // Move spacepoints into the output container to avoid unnecessary copies
260 for (FPGATrackSimCluster& cluster : spacepoints) {
261 FPGASpacePoints->push_back(std::move(cluster));
262 }
263
264 // Add spacepoint hits to appropriate stage (using FPGASpacePoints directly from StoreGate)
265 for (const auto& cluster : *FPGASpacePoints) {
266 // Keep the exact constituent hits of the spacepoint (not just the cluster-equivalent summary)
267 for (const auto& hit : cluster.getHitList()) {
268 (m_secondStageStrips ? phits_2nd : phits_1st).emplace_back(&hit, [](const FPGATrackSimHit*){});
269 }
270 }
271 } else {
272 // If spacepoints are disabled, add strip hits from phits_strips (filled by slicing engine)
273 // These pointers point to hits in FPGAHits, which has stable lifetime in StoreGate
274 for (const FPGATrackSimHit* hit : phits_strips) {
275 (m_secondStageStrips ? phits_2nd : phits_1st).emplace_back(hit, [](const FPGATrackSimHit*){});
276 }
277 }
278
279 // VIEW_ELEMENTS - no copy, just store pointers
280 for (auto& hit : phits_2nd) {
281 FPGAHits_2nd_cdv->push_back(hit.get());
282 }
283
284 // Add all hits including SPs to this for the HoughRootOutputTool
285 for (const FPGATrackSimHit* hit : *(FPGAHits_2nd.cptr())) {
286 phits_output.emplace_back(hit, [](const FPGATrackSimHit*){});
287 }
288 ATH_MSG_DEBUG("1st stage hits: " << phits_1st.size() << " 2nd stage hits: " << phits_2nd.size() );
289 if (phits_1st.empty()) {
290 // Potentially write the output data, now it's empty and reset, but this keeps things synchronized over trees
291 if (m_writeOutputData) {
292 std::vector<FPGATrackSimRoad> roads_1st;
293 std::vector<FPGATrackSimTrack> tracks_1st;
294 auto dataFlowInfo = std::make_unique<FPGATrackSimDataFlowInfo>();
295 ATH_CHECK(writeOutputData(roads_1st, tracks_1st, dataFlowInfo.get()));
296 }
297 return StatusCode::SUCCESS;
298 }
299
300 // Get truth tracks from DataPrep as well.
302 if (!FPGATruthTracks.isValid()) {
303 ATH_MSG_ERROR("Could not find FPGA Truth Track Collection with key " << FPGATruthTracks.key());
304 return StatusCode::FAILURE;
305 }
306 // Same for offline tracks.
308 if (!FPGAOfflineTracks.isValid()) {
309 ATH_MSG_ERROR("Could not find FPGA Offline Track Collection with key " << FPGAOfflineTracks.key());
310 return StatusCode::FAILURE;
311 }
312
313
315 // roads //
317
319 const std::vector<FPGATrackSimTruthTrack>& truthtracks = *FPGATruthTracks;
321 auto nLogicalLayers = m_FPGATrackSimMapping->PlaneMap_1st(0)->getNLogiLayers();
324 auto monitorRoads = [&](auto& monitor, const auto& roads) {
325 if (!monitor.empty()) {
326 monitor->fillRoad(roads, truthtracks, nLogicalLayers);
327 }
328 };
329
330 std::vector<FPGATrackSimRoad> roads_1st;
331 {
332 std::optional<Athena::Chrono> chronoGetRoads;
333 if constexpr (enableBenchmark) chronoGetRoads.emplace("1st Stage: GetRoads", m_chrono.get());
334 // get roads
335 ATH_CHECK(m_roadFinderTool->getRoads(phits_1st, roads_1st, *(FPGATruthTracks.cptr())));
336 monitorRoads(m_1st_stage_road_monitor, roads_1st);
337 }
338
339
340 {
341 // Standard road Filter
342 std::optional<Athena::Chrono> chronoRoadFiltering;
343 if constexpr (enableBenchmark) chronoRoadFiltering.emplace("1st Stage: RoadFiltering", m_chrono.get());
344 std::vector<FPGATrackSimRoad> postfilter_roads;
345 if (m_filterRoads) {
346 ATH_CHECK(m_roadFilterTool->filterRoads(roads_1st, postfilter_roads));
347 roads_1st = std::move(postfilter_roads);
348 }
350 monitorRoads(m_1st_stage_road_post_filter_1_monitor, roads_1st);
351 }
352
353
354 {
355 // overlap removal
356 std::optional<Athena::Chrono> chronoOverlapRemoval;
357 if constexpr (enableBenchmark) chronoOverlapRemoval.emplace("1st Stage: OverlapRemoval", m_chrono.get());
358 if (m_doOverlapRemoval) ATH_CHECK(m_overlapRemovalTool_1st->runOverlapRemoval(roads_1st));
360 monitorRoads(m_1st_stage_road_post_OLR_monitor, roads_1st);
361 }
362
363
364 {
365 // Road Filter2
366 std::optional<Athena::Chrono> chronoRoadFiltering2;
367 if constexpr (enableBenchmark) chronoRoadFiltering2.emplace("1st Stage: RoadFiltering2", m_chrono.get());
368 std::vector<FPGATrackSimRoad> postfilter2_roads;
369 if (m_filterRoads2) {
370 ATH_CHECK(m_roadFilterTool2->filterRoads(roads_1st, postfilter2_roads));
371 roads_1st = std::move(postfilter2_roads);
372 }
374 monitorRoads(m_1st_stage_road_post_filter_2_monitor, roads_1st);
375 }
376
378 // tracks //
380
382 auto monitorTracks = [&](auto& monitor, const auto& tracks) {
383 if (monitor.empty()) return;
384 // prepare vector<const FPGATrackSimTrack*> regardless of input type
385 std::vector<const FPGATrackSimTrack*> track_ptrs;
386 track_ptrs.reserve(tracks.size());
387 // transform tracks into a vector of pointers
388 if constexpr (std::is_pointer_v<typename std::decay_t<decltype(tracks)>::value_type>) {
389 // tracks is std::vector<const FPGATrackSimTrack*>
390 track_ptrs.insert(track_ptrs.end(), tracks.begin(), tracks.end());
391 } else {
392 // tracks is std::vector<FPGATrackSimTrack>
393 std::transform(tracks.begin(), tracks.end(), std::back_inserter(track_ptrs), [](const auto& t) { return &t; });
394 }
395 // monitor using track pointers
396 monitor->fillTrack(track_ptrs, truthtracks, 1.e15);
397 };
398
399 std::vector<FPGATrackSimTrack> tracks_1st;
400 {
401 // Get tracks
402 std::optional<Athena::Chrono> chronoGettingTracks;
403 if constexpr (enableBenchmark) chronoGettingTracks.emplace("1st Stage: Getting Tracks", m_chrono.get());
404 if (m_doTracking) {
405 if (m_doNNTrack) {
406 ATH_MSG_DEBUG("Performing NN tracking");
407 ATH_CHECK(m_NNTrackTool->getTracks_1st(roads_1st, tracks_1st));
408 if (m_doGNNTrack) {
409 ATH_MSG_DEBUG("Performing track parameter estimation");
410 ATH_CHECK(m_NNTrackTool->setTrackParameters(tracks_1st,true,m_evtSel->getMin(), m_evtSel->getMax()));
411 }
412 } else {
413 ATH_MSG_DEBUG("Performing Linear tracking");
414 if (m_passLowestChi2TrackOnly) { // Pass only the lowest chi2 track per road
415 // Loop over roads and keep only the best track for each road
416 for (const auto& road : roads_1st) {
417 std::vector<FPGATrackSimTrack> tracksForCurrentRoad;
418
419 // Collect tracks for this road
420 std::vector<FPGATrackSimRoad> roadVec = {road};
421 ATH_CHECK(m_trackFitterTool_1st->getTracks(roadVec, tracksForCurrentRoad, m_evtSel->getMin(), m_evtSel->getMax()));
422
423 // Find the best track for this road
424 if (!tracksForCurrentRoad.empty()) {
425 auto bestTrackIter = std::min_element(
426 tracksForCurrentRoad.begin(), tracksForCurrentRoad.end(),
427 [](const FPGATrackSimTrack& a, const FPGATrackSimTrack& b) {
428 return a.getChi2ndof() < b.getChi2ndof();
429 });
430
431 if (bestTrackIter != tracksForCurrentRoad.end() && bestTrackIter->getChi2ndof() < 1.e15) {
432 tracks_1st.push_back(*bestTrackIter);
433 }
434 }
435 }
436 } else { // Pass all tracks with chi2 < 1e15
437 ATH_CHECK(m_trackFitterTool_1st->getTracks(roads_1st, tracks_1st, m_evtSel->getMin(), m_evtSel->getMax()));
438 }
439 }
440 } else { // No tracking;
441 ATH_MSG_DEBUG("No tracking. Just running dummy road2track algorith");
442 if(m_doGNNPixelSeeding) { //For GNNPixelSeeding, convert the roads to a track in the simplest form
443 for (const auto& road : roads_1st) {
444 std::vector<std::shared_ptr<const FPGATrackSimHit>> track_hits;
445 for (unsigned layer = 0; layer < road.getNLayers(); ++layer) {
446 track_hits.insert(track_hits.end(), road.getHitPtrs(layer).begin(), road.getHitPtrs(layer).end());
447 }
448
449 FPGATrackSimTrack track_cand;
450 track_cand.setNLayers(track_hits.size());
451 for (size_t ihit = 0; ihit < track_hits.size(); ++ihit) {
452 track_cand.setFPGATrackSimHit(ihit, track_hits[ihit]);
453 }
454 tracks_1st.push_back(std::move(track_cand));
455 }
456 }
457 else { roadsToTrack(roads_1st, tracks_1st, m_FPGATrackSimMapping->PlaneMap_1st(0)); }
458 }
459
460 // calculateTruth() before any monitors
461 // this explicitly calculates barcode, barcodeFrac and eventIndex
462 ATH_MSG_DEBUG("doMultiTruth = " << m_doMultiTruth);
463 if (m_doMultiTruth)
464 for (auto &track : tracks_1st)
465 track.calculateTruth();
466
469 monitorTracks(m_1st_stage_track_monitor, tracks_1st);
470 }
471
472
473 {
474 // set track parameters to truth
475 std::optional<Athena::Chrono> chronoSetTruthParams;
476 if constexpr (enableBenchmark) chronoSetTruthParams.emplace("1st Stage: Set Track Parameters to Truth", m_chrono.get());
477 //Loop over tracks and set the region for all of them, also optionally set track parameters to truth
478 for (FPGATrackSimTrack& track : tracks_1st) {
479 track.setRegion(m_region);
480 if (m_SetTruthParametersForTracks >= 0 && truthtracks.size() > 0) {
482 track.setQOverPt(truthtracks.front().getQOverPt());
483 else if (m_SetTruthParametersForTracks != 1)
484 track.setD0(truthtracks.front().getD0());
485 else if (m_SetTruthParametersForTracks != 2)
486 track.setPhi(truthtracks.front().getPhi());
487 else if (m_SetTruthParametersForTracks != 3)
488 track.setZ0(truthtracks.front().getZ0());
489 else if (m_SetTruthParametersForTracks != 4)
490 track.setEta(truthtracks.front().getEta());
491 }
492 }
495 monitorTracks(m_1st_stage_track_post_setTruth_monitor, tracks_1st);
496 }
497
498 // Loop over roads and store them in SG (after track finding to also copy the sector information)
499 for (auto const& road : roads_1st) {
500 FPGARoads_1st->push_back(road);
501 }
502
503 // Do some simple monitoring of efficiencies for truth before anything else
504 if (truthtracks.size() > 0) {
505 m_evt_truth++;
506 if (roads_1st.size() > 0) m_nRoadsFound++;
507 if (roads_1st.size() > m_maxNRoadsFound) m_maxNRoadsFound = roads_1st.size();
508 if (tracks_1st.size() > 0) {
510 if (tracks_1st.size() > m_maxNTracksTot) m_maxNTracksTot = tracks_1st.size();
511 }
512 }
513
514
515 // Apply OLR but remove tracks that failed chi2 first
516 for (auto itrack = tracks_1st.begin(); itrack != tracks_1st.end();) {
517 if (!passesChi2Cut(*itrack)) itrack = tracks_1st.erase(itrack);
518 else ++itrack;
519 }
520 // do monitoring of chi2
521 m_nTracksChi2Tot += tracks_1st.size();
523 monitorTracks(m_1st_stage_track_post_chi2_monitor, tracks_1st);
524
525 {
526 // overlap removal
527 std::optional<Athena::Chrono> chronoOverlapRemoval2;
528 if constexpr (enableBenchmark) chronoOverlapRemoval2.emplace("1st Stage: OverlapRemoval", m_chrono.get());
529 if (m_doOverlapRemoval) ATH_CHECK(m_overlapRemovalTool_1st->runOverlapRemoval(tracks_1st));
530 // monitor variables (vectors of pointers)
531 std::vector<const FPGATrackSimTrack*> tracks_1st_after_chi2;
532 std::vector<const FPGATrackSimTrack*> tracks_1st_after_overlap;
533 for (const FPGATrackSimTrack& track : tracks_1st) {
534 if (track.passedOR()) {
535 tracks_1st_after_overlap.push_back(&track);
537 }
538 }
540 monitorTracks(m_1st_stage_track_post_OLR_monitor, tracks_1st_after_overlap);
541 }
542
543 m_nRoadsTot += roads_1st.size();
544 m_nTracksTot += tracks_1st.size();
545 // Do some simple monitoring of efficiencies now for tracks passing chi2 and potentially OLR
546 if (truthtracks.size() > 0) {
547
548 unsigned npasschi2(0);
549 unsigned npasschi2OLR(0);
550 if (tracks_1st.size() > 0) {
551 for (const auto& track : tracks_1st) { // these passed the chi2
552 npasschi2++;
553 if (track.passedOR()) {
554 npasschi2OLR++;
555 }
556 }
557 }
558 if (npasschi2 > m_maxNTracksChi2Tot) m_maxNTracksChi2Tot = npasschi2;
559 if (npasschi2OLR > m_maxNTracksChi2OLRTot) m_maxNTracksChi2OLRTot = npasschi2OLR;
560 if (npasschi2 > 0) m_nTracksChi2Found++;
561 if (npasschi2OLR > 0) m_nTracksChi2OLRFound++;
562 }
563
564 // Now pick hits for seeding, this changes the tracks to have fewer hits
565 if (m_keepHitsStrategy > 0) MakeSeedTracks(tracks_1st);
566
567 for (const FPGATrackSimTrack& track : tracks_1st) {
568 FPGATracks_1stHandle->push_back(track);
569 }
570
571 // Now, we may want to do large-radius tracking on the hits not used by the first stage tracking.
572 // This follows overlap removal.
573 std::vector<FPGATrackSimRoad> roadsLRT;
574 std::vector<FPGATrackSimTrack> tracksLRT; // currently empty
575 if (m_doLRT) {
576 // Filter out hits that are on successful first-stage tracks
577 std::vector<std::shared_ptr<const FPGATrackSimHit>> remainingHits;
578
580 ATH_MSG_DEBUG("Doing hit filtering based on prompt tracks.");
581 ATH_CHECK(m_LRTRoadFilterTool->filterUsedHits(tracks_1st, phits_1st, remainingHits));
582
583 for (const auto &Hit : remainingHits) FPGAHitsFiltered_1st->push_back(new FPGATrackSimHit(*Hit));
584
585 } else {
586 ATH_MSG_DEBUG("No hit filtering requested; using all hits for LRT.");
587 remainingHits = std::move(phits_1st);
588 }
589
590 // Get LRT roads with remaining hits
591 ATH_MSG_DEBUG("Finding LRT roads");
592 ATH_CHECK(m_LRTRoadFinderTool->getRoads( remainingHits, roadsLRT ));
593 }
594
595 auto dataFlowInfo = std::make_unique<FPGATrackSimDataFlowInfo>();
596
597 // Write the output and reset
598 if (m_writeOutputData) {
599 ATH_CHECK(writeOutputData(roads_1st, tracks_1st, dataFlowInfo.get()));
600 }
601
602 // This one we can do-- by passing in truth and offline tracks via storegate above (*FPGAOfflineTracks).
604 ATH_MSG_DEBUG("Running HoughRootOutputTool in 1st stage.");
605
606 SmartIF<IEventProcessor> appMgr{service("ApplicationMgr")};
607 if (!appMgr) {
608 ATH_MSG_ERROR("Failed to retrieve ApplicationMgr as IEventProcessor");
609 return StatusCode::FAILURE;
610 }
611
612 // Create output ROOT file
613 ATH_CHECK(m_houghRootOutputTool->fillTree(tracks_1st, truthtracks, *FPGAOfflineTracks, phits_output, m_writeOutNonSPStripHits, false));
614 }
615
616 // Reset data pointers
619
620 return StatusCode::SUCCESS;
621}
622
623
625// INPUT PASSING, READING AND PROCESSING //
627
628StatusCode FPGATrackSimLogicalHitsProcessAlg::writeOutputData( const std::vector<FPGATrackSimRoad>& roads_1st,
629 std::vector<FPGATrackSimTrack> const& tracks_1st,
630 FPGATrackSimDataFlowInfo const* dataFlowInfo)
631{
633
634 ATH_MSG_DEBUG("NFPGATrackSimRoads_1st = " << roads_1st.size() << ", NFPGATrackSimTracks_1st = " << tracks_1st.size());
635
636 if (!m_writeOutputData) return StatusCode::SUCCESS;
637 m_logicEventOutputHeader->reserveFPGATrackSimRoads_1st(roads_1st.size());
638 m_logicEventOutputHeader->addFPGATrackSimRoads_1st(roads_1st);
639
640 m_logicEventOutputHeader->reserveFPGATrackSimTracks_1st(tracks_1st.size());
641 m_logicEventOutputHeader->addFPGATrackSimTracks_1st(tracks_1st);
642
643 m_logicEventOutputHeader->setDataFlowInfo(*dataFlowInfo);
644 ATH_MSG_DEBUG(m_logicEventOutputHeader->getDataFlowInfo());
645
646 // It would be nice to rearrange this so both algorithms use one instance of this tool, I think.
647 // Which means that dataprep can't call writeData because that does Fill().
648 ATH_CHECK(m_writeOutputTool->writeData());
649
650
651
652 return StatusCode::SUCCESS;
653}
654
655
657// Finalize
658
660{
661 ATH_MSG_INFO("PRINTING FPGATRACKSIM SIMPLE STATS");
662 ATH_MSG_INFO("========================================================================================");
663 ATH_MSG_INFO("Ran on events = " << m_evt);
664 ATH_MSG_INFO("Inclusive efficiency to find a road = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_nRoadsFound/(float)m_evt_truth)));
666 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)));
668 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)));
670 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)));
672 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)));
673
675 ATH_MSG_INFO("Inclusive efficiency to find a track = " << (m_evt_truth == 0 ? "NAN" : std::to_string(m_nTracksFound/(float)m_evt_truth)));
676 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)));
678 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)));
680 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)));
681 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)));
683 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)));
684 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)));
685
686
687 ATH_MSG_INFO("Number of 1st stage roads/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_nRoadsTot/(float)m_evt)));
689 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)));
691 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)));
693 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)));
695 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)));
696
698 ATH_MSG_INFO("Number of 1st stage track combinations/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_nTracksTot/(float)m_evt)));
699 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)));
701 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)));
703 ATH_MSG_INFO("Number of 1st stage tracks passing chi2/event = " << (m_evt == 0 ? "NAN" : std::to_string(m_nTracksChi2Tot/(float)m_evt)));
704 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)));
706 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)));
707 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)));
708 ATH_MSG_INFO("========================================================================================");
709
710 ATH_MSG_INFO("Max number of 1st stage roads in an event = " << m_maxNRoadsFound);
712 ATH_MSG_INFO("New Max number of 1st stage roads in an event = " << m_1st_stage_road_monitor->getMaxNElements());
714 ATH_MSG_INFO("New Max number of 1st stage roads passing filter1 in an event = " << m_1st_stage_road_post_filter_1_monitor->getMaxNElements());
716 ATH_MSG_INFO("New Max number of 1st stage roads passing OLR in an event = " << m_1st_stage_road_post_OLR_monitor->getMaxNElements());
718 ATH_MSG_INFO("New Max number of 1st stage roads passing filter2 in an event = " << m_1st_stage_road_post_filter_2_monitor->getMaxNElements());
719
721 ATH_MSG_INFO("Max number of 1st stage track combinations in an event = " << m_maxNTracksTot);
722 ATH_MSG_INFO("New Max number of 1st stage track combinations in an event = " << m_1st_stage_track_monitor->getMaxNElements());
724 ATH_MSG_INFO("New Max number of 1st stage tracks after set truth in an event = " << m_1st_stage_track_post_setTruth_monitor->getMaxNElements());
726 ATH_MSG_INFO("Max number of 1st stage tracks passing chi2 in an event = " << m_maxNTracksChi2Tot);
727 ATH_MSG_INFO("New Max number of 1st stage tracks passing chi2 in an event = " << m_1st_stage_track_post_chi2_monitor->getMaxNElements());
729 ATH_MSG_INFO("Max number of 1st stage tracks passing chi2 and OLR in an event = " << m_maxNTracksChi2OLRTot);
730 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());
731 ATH_MSG_INFO("========================================================================================");
732
733 return StatusCode::SUCCESS;
734}
735
736
738// Helpers
739
740void FPGATrackSimLogicalHitsProcessAlg::printHitSubregions(std::vector<FPGATrackSimHit> const & hits)
741{
742 ATH_MSG_WARNING("Hit regions:");
743 for (const auto& hit : hits)
744 {
745 std::vector<uint32_t> regions = m_FPGATrackSimMapping->SubRegionMap()->getRegions(hit);
746 std::stringstream ss;
747 for (auto r : regions)
748 ss << r << ",";
749 ATH_MSG_WARNING("\t[" << ss.str() << "]");
750 }
751}
752
753
754// Chi2 cut implementation
756 bool retv = track.getChi2ndof() < m_trackScoreCut.value();
757
758 if (int(track.getFPGATrackSimHitPtrs().size()) < track.getNHits())
759 ATH_MSG_FATAL("More hits than layers on track");
760
761 unsigned missedhits = track.getFPGATrackSimHitPtrs().size() - track.getNHits();
762 if ((missedhits>=m_track_Chi2PhiCut.value().size()) ||
763 (missedhits>=m_track_Chi2EtaCut.value().size())) {
764 ATH_MSG_ERROR("More missed hits than entries in Chi2 cut " <<missedhits << " " << m_track_Chi2PhiCut.value().size() << " " <<m_track_Chi2EtaCut.value().size()
765 << track.getFPGATrackSimHitPtrs().size() << " " << track.getNHits());
766 }
767
768 if (m_track_Chi2PhiCut.value().at(missedhits) > 0) {
769 retv &= track.getChi2Phi() < m_track_Chi2PhiCut.value().at(missedhits);
770 }
771 if (m_track_Chi2EtaCut.value().at(missedhits) > 0) {
772 retv &= track.getChi2Eta() < m_track_Chi2EtaCut.value().at(missedhits);
773 }
774
775
776 return retv;
777}
778
779void FPGATrackSimLogicalHitsProcessAlg::MakeSeedTracks(std::vector<FPGATrackSimTrack>& tracks)
780{
781 for (auto &track : tracks) {
782 const auto& hitptrs = track.getFPGATrackSimHitPtrs();
783 layer_bitmask_t hitmask = 0x0;
784 for (unsigned ihit = 0; ihit < hitptrs.size(); ihit++) { // can't just use hit mask directly from track because that is for coordinates
785 if (hitptrs[ihit] && hitptrs[ihit]->isReal()) hitmask |= (0x1 << ihit);
786 }
787 std::vector<unsigned> toUse = PickHitsToUse(hitmask);
788 track.setNLayers(hitptrs.size()); //clears old hits
789 for (unsigned lyrToUse : toUse) {
790 track.setFPGATrackSimHit(lyrToUse, hitptrs.at(lyrToUse));
791 }
792 }
793}
794
795
797{
798 std::vector<unsigned> toUse;
799 switch (m_keepHitsStrategy) {
800 case 1: // try and pick hits furthest apart, use only 3
801 {
802 if (hitmask == 0x1f) { // miss no hits
803 toUse = {0,2,4};
804 }
805 else if (hitmask == 0x1e) { // miss inner layer, ie layer 0
806 toUse = {1,3,4};
807 }
808 else if (hitmask == 0x1d) { // miss layer 1
809 toUse = {0,2,4};
810 }
811 else if (hitmask == 0x1b) { // miss layer 2
812 toUse = {0,3,4};
813 }
814 else if (hitmask == 0x17) { // miss layer 3
815 toUse = {0,2,4};
816 }
817 else if (hitmask == 0x0f) { // miss layer 4
818 toUse = {0,2,3};
819 }
820 }
821 break;
822 case 2: // pick inner hits, use only 3
823 {
824 if (hitmask == 0x1f) { // miss no hits
825 toUse = {0,1,2};
826 }
827 else if (hitmask == 0x1e) { // miss inner layer, ie layer 0
828 toUse = {1,2,3};
829 }
830 else if (hitmask == 0x1d) { // miss layer 1
831 toUse = {0,2,3};
832 }
833 else if (hitmask == 0x1b) { // miss layer 2
834 toUse = {0,1,3};
835 }
836 else if (hitmask == 0x17) { // miss layer 3
837 toUse = {0,1,2};
838 }
839 else if (hitmask == 0x0f) { // miss layer 4
840 toUse = {0,1,2};
841 }
842 }
843 break;
844 case 3: // pick outer hits, use only 3
845 {
846 if (hitmask == 0x1f) { // miss no hits
847 toUse = {2,3,4};
848 }
849 else if (hitmask == 0x1e) { // miss inner layer, ie layer 0
850 toUse = {2,3,4};
851 }
852 else if (hitmask == 0x1d) { // miss layer 1
853 toUse = {2,3,4};
854 }
855 else if (hitmask == 0x1b) { // miss layer 2
856 toUse = {1,3,4};
857 }
858 else if (hitmask == 0x17) { // miss layer 3
859 toUse = {1,2,4};
860 }
861 else if (hitmask == 0x0f) { // miss layer 4
862 toUse = {1,2,3};
863 }
864 }
865 break;
866 case 4: // keep 4 hits, choose middle one to drop if necessary
867 {
868 if (hitmask == 0x1f) { // miss no hits
869 toUse = {0,1,2,3};
870 }
871 else if (hitmask == 0x1e) { // miss inner layer, ie layer 0
872 toUse = {1,2,3,4};
873 }
874 else if (hitmask == 0x1d) { // miss layer 1
875 toUse = {0,2,3,4};
876 }
877 else if (hitmask == 0x1b) { // miss layer 2
878 toUse = {0,1,3,4};
879 }
880 else if (hitmask == 0x17) { // miss layer 3
881 toUse = {0,1,2,4};
882 }
883 else if (hitmask == 0x0f) { // miss layer 4
884 toUse = {0,1,2,3};
885 }
886 }
887 break;
888 }
889 return toUse;
890}
#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
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
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
virtual StatusCode execute(const EventContext &ctx) override
Execute method.
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
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