diff --git a/Examples/Algorithms/TrackFindingGnn/src/TrackFindingAlgorithmGnn.cpp b/Examples/Algorithms/TrackFindingGnn/src/TrackFindingAlgorithmGnn.cpp index 580f1de4754..3987871b913 100644 --- a/Examples/Algorithms/TrackFindingGnn/src/TrackFindingAlgorithmGnn.cpp +++ b/Examples/Algorithms/TrackFindingGnn/src/TrackFindingAlgorithmGnn.cpp @@ -226,7 +226,7 @@ ProcessCode TrackFindingAlgorithmGnn::execute( onetrack.reserve(candidate.size()); for (auto i : candidate) { - for (const auto& sl : spacePoints.at(i).sourceLinks()) { + for (const auto& sl : sortedSpacePoints.at(i).sourceLinks()) { onetrack.push_back(sl.template get().index()); } } diff --git a/Examples/Scripts/Python/gnn.py b/Examples/Scripts/Python/gnn.py index a9c02427a28..eb9ac745135 100755 --- a/Examples/Scripts/Python/gnn.py +++ b/Examples/Scripts/Python/gnn.py @@ -7,6 +7,7 @@ import acts import acts.examples import acts.examples.gnn +from acts.examples.simulation import addDigiParticleSelection, ParticleSelectorConfig from acts.examples.reconstruction import addGnn, addSpacePointsMaking from acts.examples.gnn import ( TorchMetricLearning, @@ -43,6 +44,16 @@ def runGnnMetricLearning( s=s, ) + addDigiParticleSelection( + s, + ParticleSelectorConfig( + pt=(1.0 * u.GeV, None), + eta=(-3.0, 3.0), + measurements=(7, None), + removeNeutral=True, + ), + ) + addSpacePointsMaking( s, geoSelectionConfigFile=geometrySelection, diff --git a/Examples/Scripts/Python/gnn4itk_example.py b/Examples/Scripts/Python/gnn4itk_example.py index 4edb63e834f..712117c8eb6 100644 --- a/Examples/Scripts/Python/gnn4itk_example.py +++ b/Examples/Scripts/Python/gnn4itk_example.py @@ -16,6 +16,7 @@ import acts import acts.examples from acts.examples.reconstruction import addGnn +from acts.examples.simulation import ParticleSelectorConfig, addDigiParticleSelection from acts.examples.gnn import ( ModuleMapCuda, CudaTrackBuilding, @@ -81,6 +82,15 @@ def runGNN4ITk( ) ) + # Select primary particles with minimum 7 hits and 1 GeV pT for efficiency evaluation + s.addWhiteboardAlias("particles_simulated_selected", "particles") + particleSelectorConfig = ParticleSelectorConfig( + pt=(1.0 * u.GeV, None), + hits=(7, None), + removeSecondaries=True, + ) + addDigiParticleSelection(s, particleSelectorConfig, logLevel=logLevel) + # Configure GNN stages for module map workflow # All parameters hardcoded based on ITk configuration diff --git a/Examples/Scripts/Python/gnn_module_map_odd.py b/Examples/Scripts/Python/gnn_module_map_odd.py index de45ce77c79..0681ce7d0f0 100644 --- a/Examples/Scripts/Python/gnn_module_map_odd.py +++ b/Examples/Scripts/Python/gnn_module_map_odd.py @@ -25,7 +25,7 @@ ParticleConfig, addFatras, addDigitization, - addGenParticleSelection, + addDigiParticleSelection, ParticleSelectorConfig, ) from acts.examples.reconstruction import addGnn, addSpacePointsMaking @@ -94,16 +94,6 @@ def runGnnModuleMap( rnd=rnd, ) - addGenParticleSelection( - s, - ParticleSelectorConfig( - rho=(0.0, 24 * u.mm), - absZ=(0.0, 1.0 * u.m), - eta=(-3.0, 3.0), - pt=(150 * u.MeV, None), - ), - ) - # FATRAS simulation addFatras( s, @@ -127,6 +117,16 @@ def runGnnModuleMap( logLevel=acts.logging.INFO, ) + addDigiParticleSelection( + s, + ParticleSelectorConfig( + pt=(1.0 * u.GeV, None), + eta=(-3.0, 3.0), + measurements=(7, None), + removeNeutral=True, + ), + ) + addSpacePointsMaking( s, trackingGeometry, diff --git a/Python/Examples/python/reconstruction.py b/Python/Examples/python/reconstruction.py index a9ff1a5a040..78cbacc7534 100644 --- a/Python/Examples/python/reconstruction.py +++ b/Python/Examples/python/reconstruction.py @@ -1819,6 +1819,7 @@ def addTrackWriters( writeStates: bool = False, writeFitterPerformance: bool = False, writeFinderPerformance: bool = False, + writeFinderNTuple: bool = False, logLevel: Optional[acts.logging.Level] = None, writeCovMat=False, ): @@ -1879,6 +1880,17 @@ def addTrackWriters( ) s.addWriter(trackFinderPerfWriter) + if writeFinderNTuple: + nTupleWriter = RootTrackFinderNTupleWriter( + level=customLogLevel(), + inputTracks="tracks", + inputParticles="particles_selected", + inputParticleMeasurementsMap="particle_measurements_map", + inputTrackParticleMatching="track_particle_matching", + filePath=str(Path(outputDirRoot) / f"ntuple_finding_{name}.root"), + ) + s.addWriter(nTupleWriter) + if outputDirCsv is not None: outputDirCsv = Path(outputDirCsv) if not outputDirCsv.exists(): @@ -1999,24 +2011,24 @@ def addGnn( s.addWhiteboardAlias("protoTracks", findingAlg.config.outputProtoTracks) # Convert proto tracks to tracks - s.addAlgorithm( - acts.examples.ProtoTracksToTracks( - level=customLogLevel(), - inputProtoTracks="protoTracks", - inputMeasurements="measurements", - outputTracks="tracks", - ) + convAlg = acts.examples.ProtoTracksToTracks( + level=customLogLevel(), + inputProtoTracks=findingAlg.config.outputProtoTracks, + inputMeasurements="measurements", + outputTracks="gnn-tracks", ) + s.addAlgorithm(convAlg) + s.addWhiteboardAlias("tracks", convAlg.config.outputTracks) # Truth matching matchAlg = acts.examples.TrackTruthMatcher( level=customLogLevel(), - inputTracks="tracks", - inputParticles="particles", + inputTracks=convAlg.config.outputTracks, + inputParticles="particles_selected", inputMeasurementParticlesMap="measurement_particles_map", outputTrackParticleMatching="gnn_track_particle_matching", outputParticleTrackMatching="gnn_particle_track_matching", - doubleMatching=True, + doubleMatching=False, ) s.addAlgorithm(matchAlg) s.addWhiteboardAlias( @@ -2026,21 +2038,16 @@ def addGnn( "particle_track_matching", matchAlg.config.outputParticleTrackMatching ) - # Optional performance writer - if outputDirRoot is not None: - assert ( - ACTS_EXAMPLES_ROOT_AVAILABLE - ), "ROOT output requested but ROOT is not available" - s.addWriter( - RootTrackFinderNTupleWriter( - level=customLogLevel(), - inputTracks="tracks", - inputParticles="particles", - inputParticleMeasurementsMap="particle_measurements_map", - inputTrackParticleMatching=matchAlg.config.outputTrackParticleMatching, - filePath=str(Path(outputDirRoot) / "performance_track_finding.root"), - ) - ) + addTrackWriters( + s, + name="gnn", + tracks=convAlg.config.outputTracks, + outputDirRoot=outputDirRoot, + outputDirCsv=None, + writeFinderPerformance=True, + writeSummary=False, + writeFinderNTuple=True, + ) return s diff --git a/Python/Examples/tests/root_file_hashes.txt b/Python/Examples/tests/root_file_hashes.txt index 31b990a5c7b..6ebdf7314fd 100644 --- a/Python/Examples/tests/root_file_hashes.txt +++ b/Python/Examples/tests/root_file_hashes.txt @@ -74,9 +74,12 @@ test_root_material_writer__material.root: e3b0c44298fc1c149afbf4c8996fb92427ae41 test_root_clusters_writer[configPosConstructor]__clusters.root: e842df4fe04eefff3df5f32cd1026e93286be62b8040dc700a2aff557c56dec8 test_root_clusters_writer[configKwConstructor]__clusters.root: e842df4fe04eefff3df5f32cd1026e93286be62b8040dc700a2aff557c56dec8 test_root_clusters_writer[kwargsConstructor]__clusters.root: e842df4fe04eefff3df5f32cd1026e93286be62b8040dc700a2aff557c56dec8 -test_gnn_metric_learning[gpu]__performance_track_finding.root: 3f0fb36af55441994a154ea2a93978ba1930d4e87bf043f8ae9527e283bf1894 -test_gnn_module_map[gpu-torch]__performance_track_finding.root: db5c884283f5700cc2308bdf722e35b203ae018cbf10950fb71483c253685a3a -test_gnn_module_map[gpu-onnx]__performance_track_finding.root: 80e6651bb1249407d675ba2f7fd4f2af01c4fcb9c393e7f4e526212a0102b545 +test_gnn_metric_learning[gpu]__performance_finding_gnn.root: c17fb877bb165e28db0a2b99881763093e7fc9a707c045feb6a6a6b68e0dd660 +test_gnn_metric_learning[gpu]__ntuple_finding_gnn.root: 3f0fb36af55441994a154ea2a93978ba1930d4e87bf043f8ae9527e283bf1894 +test_gnn_module_map[gpu-torch]__ntuple_finding_gnn.root: ae0c828b57f4d7b7e608fa92175af418647aece75b7ac1946bf30eb8e617d046 +test_gnn_module_map[gpu-torch]__performance_finding_gnn.root: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +test_gnn_module_map[gpu-onnx]__ntuple_finding_gnn.root: 664be95535722685effd783b148ed2cec61906aee20f5a531bedbd5253d2b101 +test_gnn_module_map[gpu-onnx]__performance_finding_gnn.root: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 test_ML_Ambiguity_Solver__performance_finding_ambiML.root: c17fb877bb165e28db0a2b99881763093e7fc9a707c045feb6a6a6b68e0dd660 test_truth_tracking_kalman[generic-0.0]__trackstates_kf.root: 42a49abcef0277ca061350cc03c1ac9841e119055e2778662ec6a731e316ecd2 test_truth_tracking_kalman[generic-0.0]__tracksummary_kf.root: bde974e07d033f9bb8e078c180d288c996f69590d6b4516625e1ec0276f327a7 diff --git a/Python/Examples/tests/test_examples.py b/Python/Examples/tests/test_examples.py index d52f6117560..ad19cf5e1a8 100644 --- a/Python/Examples/tests/test_examples.py +++ b/Python/Examples/tests/test_examples.py @@ -1095,8 +1095,9 @@ def test_gnn_metric_learning(tmp_path, trk_geo, field, assert_root_hash, hardwar if hardware == "cpu": pytest.skip("CPU not yet supported") - root_file = "performance_track_finding.root" - assert not (tmp_path / root_file).exists() + root_files = ["performance_finding_gnn.root", "ntuple_finding_gnn.root"] + for f in root_files: + assert not (tmp_path / f).exists() # Check if models exist using MODEL_STORAGE environment variable model_storage = os.environ.get("MODEL_STORAGE") @@ -1133,10 +1134,11 @@ def test_gnn_metric_learning(tmp_path, trk_geo, field, assert_root_hash, hardwar print(e.output.decode("utf-8")) raise - rfp = tmp_path / root_file - assert rfp.exists() + for f in root_files: + rfp = tmp_path / f + assert rfp.exists() - assert_root_hash(root_file, rfp) + assert_root_hash(f, rfp) @pytest.mark.odd @@ -1194,9 +1196,13 @@ def test_gnn_module_map(tmp_path, assert_root_hash, backend, hardware): ) # Verify output - output_file = tmp_path / "performance_track_finding.root" + output_file = tmp_path / "performance_finding_gnn.root" + assert output_file.exists() + assert_root_hash("performance_finding_gnn.root", output_file) + + output_file = tmp_path / "ntuple_finding_gnn.root" assert output_file.exists() - assert_root_hash("performance_track_finding.root", output_file) + assert_root_hash("ntuple_finding_gnn.root", output_file) @pytest.mark.odd