diff --git a/CI/physmon/ckf_truth_smeared.yml b/CI/physmon/ckf_truth_smeared.yml deleted file mode 100644 index 60193165ba9..00000000000 --- a/CI/physmon/ckf_truth_smeared.yml +++ /dev/null @@ -1,24 +0,0 @@ -checks: - "*": - Chi2Test: - threshold: 0.01 - KolmogorovTest: - threshold: 0.68 - RatioCheck: - threshold: 3 - ResidualCheck: - threshold: 3 - IntegralCheck: - threshold: 3 - - nHoles_vs_eta: - KolmogorovTest: - threshold: 0.25 - - nOutliers_vs_pT: - KolmogorovTest: - threshold: 0.59 - - nStates_vs_eta: - KolmogorovTest: null - IntegralCheck: null diff --git a/CI/physmon/gsf.yml b/CI/physmon/config/default.yml similarity index 100% rename from CI/physmon/gsf.yml rename to CI/physmon/config/default.yml diff --git a/CI/physmon/pythia8_ttbar_config.yml b/CI/physmon/config/pythia8_ttbar.yml similarity index 100% rename from CI/physmon/pythia8_ttbar_config.yml rename to CI/physmon/config/pythia8_ttbar.yml diff --git a/CI/physmon/simulation_config.yml b/CI/physmon/config/simulation.yml similarity index 100% rename from CI/physmon/simulation_config.yml rename to CI/physmon/config/simulation.yml diff --git a/CI/physmon/default.yml b/CI/physmon/config/trackfitting_gsf.yml similarity index 99% rename from CI/physmon/default.yml rename to CI/physmon/config/trackfitting_gsf.yml index 9a85e92618e..ecd4c4fd546 100644 --- a/CI/physmon/default.yml +++ b/CI/physmon/config/trackfitting_gsf.yml @@ -10,4 +10,3 @@ checks: threshold: 3 IntegralCheck: threshold: 3 - diff --git a/CI/physmon/gx2f.yml b/CI/physmon/config/trackfitting_gx2f.yml similarity index 100% rename from CI/physmon/gx2f.yml rename to CI/physmon/config/trackfitting_gx2f.yml diff --git a/CI/physmon/truth_tracking.yml b/CI/physmon/config/trackfitting_kf.yml similarity index 100% rename from CI/physmon/truth_tracking.yml rename to CI/physmon/config/trackfitting_kf.yml diff --git a/CI/physmon/tracksummary_ckf_config.yml b/CI/physmon/config/tracksummary_ckf.yml similarity index 100% rename from CI/physmon/tracksummary_ckf_config.yml rename to CI/physmon/config/tracksummary_ckf.yml diff --git a/CI/physmon/vertexing_config.yml b/CI/physmon/config/vertexing_4muon_50vertices.yml similarity index 100% rename from CI/physmon/vertexing_config.yml rename to CI/physmon/config/vertexing_4muon_50vertices.yml diff --git a/CI/physmon/vertexing_ttbar_config.yml b/CI/physmon/config/vertexing_ttbar_pu200.yml similarity index 100% rename from CI/physmon/vertexing_ttbar_config.yml rename to CI/physmon/config/vertexing_ttbar_pu200.yml diff --git a/CI/physmon/phys_perf_mon.sh b/CI/physmon/phys_perf_mon.sh index 2ebf4d2bb5d..9fc97ab8c5f 100755 --- a/CI/physmon/phys_perf_mon.sh +++ b/CI/physmon/phys_perf_mon.sh @@ -20,17 +20,18 @@ shopt -s extglob mode=${1:-all} -if ! [[ $mode = @(all|kalman|gsf|gx2f|fullchains|vertexing|simulation) ]]; then - echo "Usage: $0 (outdir)" +if ! [[ $mode = @(all|kf|gsf|gx2f|fullchains|simulation) ]]; then + echo "Usage: $0 (outdir)" exit 1 fi outdir=${2:-physmon} mkdir -p $outdir +mkdir -p $outdir/data +mkdir -p $outdir/html +mkdir -p $outdir/logs refdir=CI/physmon/reference -refcommit=$(cat $refdir/commit) -commit=$(git rev-parse --short HEAD) SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) # File to accumulate the histcmp results @@ -123,38 +124,37 @@ function run_physmon_gen() { script=CI/physmon/workflows/physmon_${slug}.py - measure "$title" "$slug" ${script} $outdir 2>&1 > $outdir/run_${slug}.log + mkdir -p $outdir/data/$slug + mkdir -p $outdir/logs + measure "$title" "$slug" ${script} $outdir/data/$slug 2>&1 > $outdir/logs/${slug}.log this_ec=$? ec=$(($ec | $this_ec)) if [ $this_ec -ne 0 ]; then - echo "::error::🟥 Dataset generation failed: ${script} -> ec=$this_ec" + echo "::error::🟥 Dataset generation failed: ${script} -> ec=$this_ec" else - echo "::notice::✅ Dataset generation succeeded: ${script}" + echo "::notice::✅ Dataset generation succeeded: ${script}" fi } echo "::group::Generate validation dataset" -if [[ "$mode" == "all" || "$mode" == "kalman" ]]; then - run_physmon_gen "Truth Tracking KF" "truth_tracking_kalman" +if [[ "$mode" == "all" || "$mode" == "simulation" ]]; then + run_physmon_gen "Simulation" "simulation" +fi +if [[ "$mode" == "all" || "$mode" == "kf" ]]; then + run_physmon_gen "Truth Tracking KF" "trackfitting_kf" fi if [[ "$mode" == "all" || "$mode" == "gsf" ]]; then - run_physmon_gen "Truth Tracking GSF" "truth_tracking_gsf" + run_physmon_gen "Truth Tracking GSF" "trackfitting_gsf" fi if [[ "$mode" == "all" || "$mode" == "gx2f" ]]; then - run_physmon_gen "Truth Tracking GX2F" "truth_tracking_gx2f" + run_physmon_gen "Truth Tracking GX2F" "trackfitting_gx2f" fi if [[ "$mode" == "all" || "$mode" == "fullchains" ]]; then - run_physmon_gen "CKF Tracking" "ckf_tracking" - run_physmon_gen "Track finding ttbar" "track_finding_ttbar" - -fi -if [[ "$mode" == "all" || "$mode" == "vertexing" ]]; then - run_physmon_gen "Vertexing" "vertexing" -fi -if [[ "$mode" == "all" || "$mode" == "simulation" ]]; then - run_physmon_gen "Simulation" "simulation" + run_physmon_gen "CKF single muon" "trackfinding_1muon" + run_physmon_gen "CKF muon 50" "trackfinding_4muon_50vertices" + run_physmon_gen "CKF ttbar 200" "trackfinding_ttbar_pu200" fi echo "::endgroup::" @@ -163,315 +163,264 @@ function run_histcmp() { a=$1 b=$2 title=$3 - slug=$4 - shift 4 + html_path=$4 + plots_path=$5 + shift 5 echo "::group::Comparing $a vs. $b" if [ ! -f "$a" ]; then - echo "::error::histcmp failed: File $a does not exist" - ec=1 + echo "::error::histcmp failed: File $a does not exist" + ec=1 fi if [ ! -f "$b" ]; then - echo "::error::histcmp failed: File $b does not exist" - ec=1 + echo "::error::histcmp failed: File $b does not exist" + ec=1 fi run histcmp $a $b \ --label-reference=reference \ --label-monitored=monitored \ --title="$title" \ - -o $outdir/${slug}.html \ - -p $outdir/${slug}_plots \ + -o $outdir/html/$html_path \ + -p $outdir/html/$plots_path \ "$@" this_ec=$? ec=$(($ec | $this_ec)) if [ $this_ec -ne 0 ]; then - echo "::error::histcmp failed (${slug}): ec=$this_ec" + echo "::error::histcmp failed: ec=$this_ec" fi - echo "\"${title}\",${slug},${this_ec}" >> $histcmp_results + echo "\"${title}\",html/${html_path},${this_ec}" >> $histcmp_results echo "::endgroup::" } -function full_chain() { - suffix=$1 +function trackfinding() { + name=$1 + path=$2 - config="CI/physmon/ckf_${suffix}.yml" + default_config="CI/physmon/config/default.yml" - if [ ! -f "$config" ]; then - config="CI/physmon/default.yml" - fi - echo $config - - if [ $suffix != truth_smeared ]; then - run_histcmp \ - $outdir/performance_seeding_${suffix}.root \ - $refdir/performance_seeding_${suffix}.root \ - "Seeding ${suffix}" \ - seeding_${suffix} \ - -c $config + if [ -f $refdir/$path/performance_seeding.root ]; then + run_histcmp \ + $outdir/data/$path/performance_seeding.root \ + $refdir/$path/performance_seeding.root \ + "Seeding ${name}" \ + $path/performance_seeding.html \ + $path/performance_seeding_plots \ + --config $default_config fi run_histcmp \ - $outdir/performance_ckf_${suffix}.root \ - $refdir/performance_ckf_${suffix}.root \ - "CKF ${suffix}" \ - ckf_${suffix} \ - -c $config + $outdir/data/$path/performance_ckf.root \ + $refdir/$path/performance_ckf.root \ + "CKF | ${name}" \ + $path/performance_ckf.html \ + $path/performance_ckf_plots \ + --config $default_config run Examples/Scripts/generic_plotter.py \ - $outdir/performance_ivf_${suffix}.root \ - vertexing \ - $outdir/performance_ivf_${suffix}_hist.root \ + $outdir/data/$path/tracksummary_ckf.root \ + tracksummary \ + $outdir/data/$path/tracksummary_ckf_hist.root \ --silent \ - --config CI/physmon/vertexing_config.yml + --config CI/physmon/config/tracksummary_ckf.yml ec=$(($ec | $?)) # remove ntuple file because it's large - rm $outdir/performance_ivf_${suffix}.root + rm $outdir/data/$path/tracksummary_ckf.root run_histcmp \ - $outdir/performance_ivf_${suffix}_hist.root \ - $refdir/performance_ivf_${suffix}_hist.root \ - "IVF ${suffix}" \ - ivf_${suffix} + $outdir/data/$path/tracksummary_ckf_hist.root \ + $refdir/$path/tracksummary_ckf_hist.root \ + "Track Summary CKF | ${name}" \ + $path/tracksummary_ckf.html \ + $path/tracksummary_ckf_plots - run Examples/Scripts/generic_plotter.py \ - $outdir/performance_amvf_${suffix}.root \ - vertexing \ - $outdir/performance_amvf_${suffix}_hist.root \ - --silent \ - --config CI/physmon/vertexing_config.yml - ec=$(($ec | $?)) + if [ -f $refdir/$path/performance_ckf_ambi.root ]; then + run_histcmp \ + $outdir/data/$path/performance_ckf_ambi.root \ + $refdir/$path/performance_ckf_ambi.root \ + "Ambisolver | ${name}" \ + $path/performance_ckf_ambi.html \ + $path/performance_ckf_ambi + fi +} - # remove ntuple file because it's large - rm $outdir/performance_amvf_${suffix}.root +function vertexing() { + name=$1 + path=$2 + config=$3 - run_histcmp \ - $outdir/performance_amvf_${suffix}_hist.root \ - $refdir/performance_amvf_${suffix}_hist.root \ - "AMVF ${suffix}" \ - amvf_${suffix} - - if [ $suffix == seeded ]; then - run Examples/Scripts/generic_plotter.py \ - $outdir/performance_amvf_gridseeder_${suffix}.root \ + if [ -f $refdir/$path/performance_vertexing_ivf_notime_hist.root ]; then + run Examples/Scripts/generic_plotter.py \ + $outdir/data/$path/performance_vertexing_ivf_notime.root \ vertexing \ - $outdir/performance_amvf_gridseeder_${suffix}_hist.root \ + $outdir/data/$path/performance_vertexing_ivf_notime_hist.root \ --silent \ - --config CI/physmon/vertexing_config.yml + --config $config ec=$(($ec | $?)) # remove ntuple file because it's large - rm $outdir/performance_amvf_gridseeder_${suffix}.root + rm $outdir/data/$path/performance_vertexing_ivf_notime.root run_histcmp \ - $outdir/performance_amvf_gridseeder_${suffix}_hist.root \ - $refdir/performance_amvf_gridseeder_${suffix}_hist.root \ - "AMVF (+grid seeder) ${suffix}" \ - amvf_gridseeder_${suffix} + $outdir/data/$path/performance_vertexing_ivf_notime_hist.root \ + $refdir/$path/performance_vertexing_ivf_notime_hist.root \ + "IVF notime | ${name}" \ + $path/performance_vertexing_ivf_notime.html \ + $path/performance_vertexing_ivf_notime_plots fi run Examples/Scripts/generic_plotter.py \ - $outdir/tracksummary_ckf_${suffix}.root \ - tracksummary \ - $outdir/tracksummary_ckf_${suffix}_hist.root \ + $outdir/data/$path/performance_vertexing_amvf_gauss_notime.root \ + vertexing \ + $outdir/data/$path/performance_vertexing_amvf_gauss_notime_hist.root \ --silent \ - --config CI/physmon/tracksummary_ckf_config.yml + --config $config ec=$(($ec | $?)) # remove ntuple file because it's large - rm $outdir/tracksummary_ckf_${suffix}.root + rm $outdir/data/$path/performance_vertexing_amvf_gauss_notime.root run_histcmp \ - $outdir/tracksummary_ckf_${suffix}_hist.root \ - $refdir/tracksummary_ckf_${suffix}_hist.root \ - "Track Summary CKF ${suffix}" \ - tracksummary_ckf_${suffix} - -} - -function simulation() { - suffix=$1 - - config="CI/physmon/simulation_config.yml" + $outdir/data/$path/performance_vertexing_amvf_gauss_notime_hist.root \ + $refdir/$path/performance_vertexing_amvf_gauss_notime_hist.root \ + "AMVF gauss notime | ${name}" \ + $path/performance_vertexing_amvf_gauss_notime.html \ + $path/performance_vertexing_amvf_gauss_notime_plots run Examples/Scripts/generic_plotter.py \ - $outdir/particles_${suffix}.root \ - particles \ - $outdir/particles_${suffix}_hist.root \ + $outdir/data/$path/performance_vertexing_amvf_grid_time.root \ + vertexing \ + $outdir/data/$path/performance_vertexing_amvf_grid_time_hist.root \ --silent \ --config $config ec=$(($ec | $?)) # remove ntuple file because it's large - rm $outdir/particles_${suffix}.root + rm $outdir/data/$path/performance_vertexing_amvf_grid_time.root run_histcmp \ - $outdir/particles_${suffix}_hist.root \ - $refdir/particles_${suffix}_hist.root \ - "Particles ${suffix}" \ - particles_${suffix} + $outdir/data/$path/performance_vertexing_amvf_grid_time_hist.root \ + $refdir/$path/performance_vertexing_amvf_grid_time_hist.root \ + "AMVF grid time | ${name}" \ + $path/performance_vertexing_amvf_grid_time.html \ + $path/performance_vertexing_amvf_grid_time_plots } -if [[ "$mode" == "all" || "$mode" == "fullchains" ]]; then - full_chain truth_smeared - full_chain truth_estimated - full_chain seeded - full_chain orthogonal - - run_histcmp \ - $outdir/performance_ambi_seeded.root \ - $refdir/performance_ambi_seeded.root \ - "Ambisolver seeded" \ - ambi_seeded - - run_histcmp \ - $outdir/performance_ambi_orthogonal.root \ - $refdir/performance_ambi_orthogonal.root \ - "Ambisolver orthogonal" \ - ambi_orthogonal - - run_histcmp \ - $outdir/performance_seeding_ttbar.root \ - $refdir/performance_seeding_ttbar.root \ - "Seeding ttbar" \ - seeding_ttbar \ - -c $config - - run_histcmp \ - $outdir/performance_ckf_ttbar.root \ - $refdir/performance_ckf_ttbar.root \ - "CKF ttbar" \ - ckf_ttbar \ - -c $config +function simulation() { + suffix=$1 - run_histcmp \ - $outdir/performance_ambi_ttbar.root \ - $refdir/performance_ambi_ttbar.root \ - "Ambisolver " \ - ambi_ttbar + config="CI/physmon/config/simulation.yml" run Examples/Scripts/generic_plotter.py \ - $outdir/performance_amvf_ttbar.root \ - vertexing \ - $outdir/performance_amvf_ttbar_hist.root \ + $outdir/data/simulation/particles_${suffix}.root \ + particles \ + $outdir/data/simulation/particles_${suffix}_hist.root \ --silent \ - --config CI/physmon/vertexing_ttbar_config.yml - ec=$(($ec | $?)) - - run Examples/Scripts/generic_plotter.py \ - $outdir/tracksummary_ckf_ttbar.root \ - tracksummary \ - $outdir/tracksummary_ckf_ttbar_hist.root \ - --config CI/physmon/tracksummary_ckf_config.yml + --config $config ec=$(($ec | $?)) # remove ntuple file because it's large - rm $outdir/tracksummary_ckf_ttbar.root + rm $outdir/data/simulation/particles_${suffix}.root run_histcmp \ - $outdir/tracksummary_ckf_ttbar_hist.root \ - $refdir/tracksummary_ckf_ttbar_hist.root \ - "Track Summary CKF ttbar" \ - tracksummary_ckf_ttbar + $outdir/data/simulation/particles_${suffix}_hist.root \ + $refdir/simulation/particles_${suffix}_hist.root \ + "Particles ${suffix}" \ + simulation/particles_${suffix}.html \ + simulation/particles_${suffix}_plots +} +function generation() { + run Examples/Scripts/generic_plotter.py \ + $outdir/data/simulation/particles_ttbar.root \ + particles \ + $outdir/data/simulation/particles_ttbar_hist.root \ + --silent \ + --config CI/physmon/config/pythia8_ttbar.yml + # remove ntuple file because it's large - rm $outdir/performance_amvf_ttbar.root + rm $outdir/data/simulation/particles_ttbar.root run_histcmp \ - $outdir/performance_amvf_ttbar_hist.root \ - $refdir/performance_amvf_ttbar_hist.root \ - "AMVF ttbar" \ - amvf_ttbar + $outdir/data/simulation/particles_ttbar_hist.root \ + $refdir/simulation/particles_ttbar_hist.root \ + "Particles ttbar" \ + simulation/particles_ttbar.html \ + simulation/particles_ttbar_plots run Examples/Scripts/generic_plotter.py \ - $outdir/performance_amvf_gridseeder_ttbar.root \ - vertexing \ - $outdir/performance_amvf_gridseeder_ttbar_hist.root \ + $outdir/data/simulation/vertices_ttbar.root \ + vertices \ + $outdir/data/simulation/vertices_ttbar_hist.root \ --silent \ - --config CI/physmon/vertexing_ttbar_config.yml - ec=$(($ec | $?)) + --config CI/physmon/config/pythia8_ttbar.yml # remove ntuple file because it's large - rm $outdir/performance_amvf_gridseeder_ttbar.root + rm $outdir/data/simulation/vertices_ttbar.root run_histcmp \ - $outdir/performance_amvf_gridseeder_ttbar_hist.root \ - $refdir/performance_amvf_gridseeder_ttbar_hist.root \ - "AMVF (+grid seeder) ttbar" \ - amvf_gridseeder_ttbar - - run Examples/Scripts/generic_plotter.py \ - $outdir/pythia8_particles_ttbar.root \ - particles \ - $outdir/particles_ttbar_hist.root \ - --silent \ - --config CI/physmon/pythia8_ttbar_config.yml + $outdir/data/simulation/vertices_ttbar_hist.root \ + $refdir/simulation/vertices_ttbar_hist.root \ + "Vertices ttbar" \ + simulation/vertices_ttbar.html \ + simulation/vertices_ttbar_plots +} - run_histcmp \ - $outdir/particles_ttbar_hist.root \ - $refdir/particles_ttbar_hist.root \ - "Particles ttbar" \ - particles_ttbar +if [[ "$mode" == "all" || "$mode" == "simulation" ]]; then + simulation fatras + simulation geant4 - run Examples/Scripts/generic_plotter.py \ - $outdir/pythia8_vertices_ttbar.root \ - vertices \ - $outdir/vertices_ttbar_hist.root \ - --silent \ - --config CI/physmon/pythia8_ttbar_config.yml + generation +fi +if [[ "$mode" == "all" || "$mode" == "kf" ]]; then run_histcmp \ - $outdir/vertices_ttbar_hist.root \ - $refdir/vertices_ttbar_hist.root \ - "Vertices ttbar" \ - vertices_ttbar + $outdir/data/trackfitting_kf/performance_trackfitting.root \ + $refdir/trackfitting_kf/performance_trackfitting.root \ + "Truth tracking (KF)" \ + trackfitting_kf/performance_trackfitting.html \ + trackfitting_kf/performance_trackfitting_plots \ + --config CI/physmon/config/trackfitting_kf.yml fi if [[ "$mode" == "all" || "$mode" == "gsf" ]]; then run_histcmp \ - $outdir/performance_gsf.root \ - $refdir/performance_gsf.root \ + $outdir/data/trackfitting_gsf/performance_trackfitting.root \ + $refdir/trackfitting_gsf/performance_trackfitting.root \ "Truth tracking (GSF)" \ - gsf \ - -c CI/physmon/gsf.yml -fi - -if [[ "$mode" == "all" || "$mode" == "kalman" ]]; then - run_histcmp \ - $outdir/performance_truth_tracking.root \ - $refdir/performance_truth_tracking.root \ - "Truth tracking" \ - truth_tracking \ - -c CI/physmon/truth_tracking.yml + trackfitting_gsf/performance_trackfitting.html \ + trackfitting_gsf/performance_trackfitting_plots \ + --config CI/physmon/config/trackfitting_gsf.yml fi if [[ "$mode" == "all" || "$mode" == "gx2f" ]]; then run_histcmp \ - $outdir/performance_gx2f.root \ - $refdir/performance_gx2f.root \ + $outdir/data/trackfitting_gx2f/performance_trackfitting.root \ + $refdir/trackfitting_gx2f/performance_trackfitting.root \ "Truth tracking (GX2F)" \ - gx2f \ - -c CI/physmon/gx2f.yml + trackfitting_gx2f/performance_trackfitting.html \ + trackfitting_gx2f/performance_trackfitting_plots \ + --config CI/physmon/config/trackfitting_gx2f.yml fi -if [[ "$mode" == "all" || "$mode" == "vertexing" ]]; then - run Examples/Scripts/vertex_mu_scan.py \ - $outdir/performance_vertexing_*mu*.root \ - $outdir/vertexing_mu_scan.pdf +if [[ "$mode" == "all" || "$mode" == "fullchains" ]]; then + trackfinding "trackfinding | single muon | truth smeared seeding" trackfinding_1muon/truth_smeared + trackfinding "trackfinding | single muon | truth estimated seeding" trackfinding_1muon/truth_estimated + trackfinding "trackfinding | single muon | default seeding" trackfinding_1muon/seeded + trackfinding "trackfinding | single muon | orthogonal seeding" trackfinding_1muon/orthogonal - rm $outdir/performance_vertexing_*mu* -fi + trackfinding "trackfinding | 4 muon x 50 vertices | default seeding" trackfinding_4muon_50vertices + vertexing "trackfinding | 4 muon x 50 vertices | default seeding" trackfinding_4muon_50vertices CI/physmon/config/vertexing_4muon_50vertices.yml -if [[ "$mode" == "all" || "$mode" == "simulation" ]]; then - simulation fatras - simulation geant4 + trackfinding "trackfinding | ttbar with 200 pileup | default seeding" trackfinding_ttbar_pu200 + vertexing "trackfinding | ttbar with 200 pileup | default seeding" trackfinding_ttbar_pu200 CI/physmon/config/vertexing_ttbar_pu200.yml fi run CI/physmon/summary.py $histcmp_results \ diff --git a/CI/physmon/reference/commit b/CI/physmon/reference/commit deleted file mode 100644 index bb8d9b15173..00000000000 --- a/CI/physmon/reference/commit +++ /dev/null @@ -1 +0,0 @@ -610a3fa diff --git a/CI/physmon/reference/performance_ambi_orthogonal.root b/CI/physmon/reference/performance_ambi_orthogonal.root deleted file mode 100644 index 0b90c87805d..00000000000 Binary files a/CI/physmon/reference/performance_ambi_orthogonal.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ambi_seeded.root b/CI/physmon/reference/performance_ambi_seeded.root deleted file mode 100644 index 27dbfdb416e..00000000000 Binary files a/CI/physmon/reference/performance_ambi_seeded.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ambi_ttbar.root b/CI/physmon/reference/performance_ambi_ttbar.root deleted file mode 100644 index 2dd55c52b42..00000000000 Binary files a/CI/physmon/reference/performance_ambi_ttbar.root and /dev/null differ diff --git a/CI/physmon/reference/performance_amvf_gridseeder_seeded_hist.root b/CI/physmon/reference/performance_amvf_gridseeder_seeded_hist.root deleted file mode 100644 index 6cea895170f..00000000000 Binary files a/CI/physmon/reference/performance_amvf_gridseeder_seeded_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_amvf_gridseeder_ttbar_hist.root b/CI/physmon/reference/performance_amvf_gridseeder_ttbar_hist.root deleted file mode 100644 index 312055b4dfc..00000000000 Binary files a/CI/physmon/reference/performance_amvf_gridseeder_ttbar_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_amvf_orthogonal_hist.root b/CI/physmon/reference/performance_amvf_orthogonal_hist.root deleted file mode 100644 index f184cb85191..00000000000 Binary files a/CI/physmon/reference/performance_amvf_orthogonal_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_amvf_seeded_hist.root b/CI/physmon/reference/performance_amvf_seeded_hist.root deleted file mode 100644 index a93155fe12b..00000000000 Binary files a/CI/physmon/reference/performance_amvf_seeded_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_amvf_truth_estimated_hist.root b/CI/physmon/reference/performance_amvf_truth_estimated_hist.root deleted file mode 100644 index 28b36526661..00000000000 Binary files a/CI/physmon/reference/performance_amvf_truth_estimated_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_amvf_truth_smeared_hist.root b/CI/physmon/reference/performance_amvf_truth_smeared_hist.root deleted file mode 100644 index 53703832364..00000000000 Binary files a/CI/physmon/reference/performance_amvf_truth_smeared_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_amvf_ttbar_hist.root b/CI/physmon/reference/performance_amvf_ttbar_hist.root deleted file mode 100644 index 47d53557498..00000000000 Binary files a/CI/physmon/reference/performance_amvf_ttbar_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ckf_orthogonal.root b/CI/physmon/reference/performance_ckf_orthogonal.root deleted file mode 100644 index 1649924f0e4..00000000000 Binary files a/CI/physmon/reference/performance_ckf_orthogonal.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ckf_seeded.root b/CI/physmon/reference/performance_ckf_seeded.root deleted file mode 100644 index 1e4d7392a93..00000000000 Binary files a/CI/physmon/reference/performance_ckf_seeded.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ckf_truth_estimated.root b/CI/physmon/reference/performance_ckf_truth_estimated.root deleted file mode 100644 index f48c7f92896..00000000000 Binary files a/CI/physmon/reference/performance_ckf_truth_estimated.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ckf_truth_smeared.root b/CI/physmon/reference/performance_ckf_truth_smeared.root deleted file mode 100644 index 0311e42de0d..00000000000 Binary files a/CI/physmon/reference/performance_ckf_truth_smeared.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ckf_ttbar.root b/CI/physmon/reference/performance_ckf_ttbar.root deleted file mode 100644 index 6a97b0ab1b4..00000000000 Binary files a/CI/physmon/reference/performance_ckf_ttbar.root and /dev/null differ diff --git a/CI/physmon/reference/performance_gsf.root b/CI/physmon/reference/performance_gsf.root deleted file mode 100644 index c6eb98c5d55..00000000000 Binary files a/CI/physmon/reference/performance_gsf.root and /dev/null differ diff --git a/CI/physmon/reference/performance_gx2f.root b/CI/physmon/reference/performance_gx2f.root deleted file mode 100644 index 5ef556b0cda..00000000000 Binary files a/CI/physmon/reference/performance_gx2f.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ivf_orthogonal_hist.root b/CI/physmon/reference/performance_ivf_orthogonal_hist.root deleted file mode 100644 index 1fd1a743e75..00000000000 Binary files a/CI/physmon/reference/performance_ivf_orthogonal_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ivf_seeded_hist.root b/CI/physmon/reference/performance_ivf_seeded_hist.root deleted file mode 100644 index e2559f1677f..00000000000 Binary files a/CI/physmon/reference/performance_ivf_seeded_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ivf_truth_estimated_hist.root b/CI/physmon/reference/performance_ivf_truth_estimated_hist.root deleted file mode 100644 index 265d2cdb22e..00000000000 Binary files a/CI/physmon/reference/performance_ivf_truth_estimated_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_ivf_truth_smeared_hist.root b/CI/physmon/reference/performance_ivf_truth_smeared_hist.root deleted file mode 100644 index 89ebd7fbd05..00000000000 Binary files a/CI/physmon/reference/performance_ivf_truth_smeared_hist.root and /dev/null differ diff --git a/CI/physmon/reference/performance_seeding_orthogonal.root b/CI/physmon/reference/performance_seeding_orthogonal.root deleted file mode 100644 index 5c4e9cdc74c..00000000000 Binary files a/CI/physmon/reference/performance_seeding_orthogonal.root and /dev/null differ diff --git a/CI/physmon/reference/performance_seeding_seeded.root b/CI/physmon/reference/performance_seeding_seeded.root deleted file mode 100644 index 2d98b74cc7c..00000000000 Binary files a/CI/physmon/reference/performance_seeding_seeded.root and /dev/null differ diff --git a/CI/physmon/reference/performance_seeding_truth_estimated.root b/CI/physmon/reference/performance_seeding_truth_estimated.root deleted file mode 100644 index a54c6c88298..00000000000 Binary files a/CI/physmon/reference/performance_seeding_truth_estimated.root and /dev/null differ diff --git a/CI/physmon/reference/performance_seeding_ttbar.root b/CI/physmon/reference/performance_seeding_ttbar.root deleted file mode 100644 index 2c24c7319d8..00000000000 Binary files a/CI/physmon/reference/performance_seeding_ttbar.root and /dev/null differ diff --git a/CI/physmon/reference/performance_truth_tracking.root b/CI/physmon/reference/performance_truth_tracking.root deleted file mode 100644 index 80b20677291..00000000000 Binary files a/CI/physmon/reference/performance_truth_tracking.root and /dev/null differ diff --git a/CI/physmon/reference/particles_fatras_hist.root b/CI/physmon/reference/simulation/particles_fatras_hist.root similarity index 86% rename from CI/physmon/reference/particles_fatras_hist.root rename to CI/physmon/reference/simulation/particles_fatras_hist.root index 8b78d8977b0..9bb02761ed4 100644 Binary files a/CI/physmon/reference/particles_fatras_hist.root and b/CI/physmon/reference/simulation/particles_fatras_hist.root differ diff --git a/CI/physmon/reference/particles_geant4_hist.root b/CI/physmon/reference/simulation/particles_geant4_hist.root similarity index 84% rename from CI/physmon/reference/particles_geant4_hist.root rename to CI/physmon/reference/simulation/particles_geant4_hist.root index 25fa6399363..bd99cf9b723 100644 Binary files a/CI/physmon/reference/particles_geant4_hist.root and b/CI/physmon/reference/simulation/particles_geant4_hist.root differ diff --git a/CI/physmon/reference/particles_ttbar_hist.root b/CI/physmon/reference/simulation/particles_ttbar_hist.root similarity index 87% rename from CI/physmon/reference/particles_ttbar_hist.root rename to CI/physmon/reference/simulation/particles_ttbar_hist.root index 6f822d306a7..9100c71418a 100644 Binary files a/CI/physmon/reference/particles_ttbar_hist.root and b/CI/physmon/reference/simulation/particles_ttbar_hist.root differ diff --git a/CI/physmon/reference/vertices_ttbar_hist.root b/CI/physmon/reference/simulation/vertices_ttbar_hist.root similarity index 93% rename from CI/physmon/reference/vertices_ttbar_hist.root rename to CI/physmon/reference/simulation/vertices_ttbar_hist.root index dd1e71ede26..9e54eaed90e 100644 Binary files a/CI/physmon/reference/vertices_ttbar_hist.root and b/CI/physmon/reference/simulation/vertices_ttbar_hist.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/orthogonal/performance_ckf.root b/CI/physmon/reference/trackfinding_1muon/orthogonal/performance_ckf.root new file mode 100644 index 00000000000..d11ff3546ab Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/orthogonal/performance_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/orthogonal/performance_seeding.root b/CI/physmon/reference/trackfinding_1muon/orthogonal/performance_seeding.root new file mode 100644 index 00000000000..d55d3833570 Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/orthogonal/performance_seeding.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/orthogonal/tracksummary_ckf_hist.root b/CI/physmon/reference/trackfinding_1muon/orthogonal/tracksummary_ckf_hist.root new file mode 100644 index 00000000000..ed8076f3217 Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/orthogonal/tracksummary_ckf_hist.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/seeded/performance_ckf.root b/CI/physmon/reference/trackfinding_1muon/seeded/performance_ckf.root new file mode 100644 index 00000000000..515090462a0 Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/seeded/performance_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/seeded/performance_seeding.root b/CI/physmon/reference/trackfinding_1muon/seeded/performance_seeding.root new file mode 100644 index 00000000000..0c64e9fe631 Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/seeded/performance_seeding.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/seeded/tracksummary_ckf_hist.root b/CI/physmon/reference/trackfinding_1muon/seeded/tracksummary_ckf_hist.root new file mode 100644 index 00000000000..c5addb4d78b Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/seeded/tracksummary_ckf_hist.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_ckf.root b/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_ckf.root new file mode 100644 index 00000000000..3feb0e1e4c0 Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_seeding.root b/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_seeding.root new file mode 100644 index 00000000000..06abee42be7 Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/truth_estimated/performance_seeding.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/truth_estimated/tracksummary_ckf_hist.root b/CI/physmon/reference/trackfinding_1muon/truth_estimated/tracksummary_ckf_hist.root new file mode 100644 index 00000000000..9ce90f1355b Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/truth_estimated/tracksummary_ckf_hist.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/truth_smeared/performance_ckf.root b/CI/physmon/reference/trackfinding_1muon/truth_smeared/performance_ckf.root new file mode 100644 index 00000000000..be2ac6376d8 Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/truth_smeared/performance_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_1muon/truth_smeared/tracksummary_ckf_hist.root b/CI/physmon/reference/trackfinding_1muon/truth_smeared/tracksummary_ckf_hist.root new file mode 100644 index 00000000000..632d9583785 Binary files /dev/null and b/CI/physmon/reference/trackfinding_1muon/truth_smeared/tracksummary_ckf_hist.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_ckf.root b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_ckf.root new file mode 100644 index 00000000000..6a6ecc7d054 Binary files /dev/null and b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_ckf_ambi.root b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_ckf_ambi.root new file mode 100644 index 00000000000..49e0fcda2c1 Binary files /dev/null and b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_ckf_ambi.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_seeding.root b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_seeding.root new file mode 100644 index 00000000000..0a59b0fba85 Binary files /dev/null and b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_seeding.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_gauss_notime_hist.root b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_gauss_notime_hist.root new file mode 100644 index 00000000000..b72a71cbb42 Binary files /dev/null and b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_gauss_notime_hist.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root new file mode 100644 index 00000000000..fed2ae9c28e Binary files /dev/null and b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_amvf_grid_time_hist.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_ivf_notime_hist.root b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_ivf_notime_hist.root new file mode 100644 index 00000000000..377bf998d6c Binary files /dev/null and b/CI/physmon/reference/trackfinding_4muon_50vertices/performance_vertexing_ivf_notime_hist.root differ diff --git a/CI/physmon/reference/trackfinding_4muon_50vertices/tracksummary_ckf_hist.root b/CI/physmon/reference/trackfinding_4muon_50vertices/tracksummary_ckf_hist.root new file mode 100644 index 00000000000..07ad96265d6 Binary files /dev/null and b/CI/physmon/reference/trackfinding_4muon_50vertices/tracksummary_ckf_hist.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf.root new file mode 100644 index 00000000000..2a692f3d751 Binary files /dev/null and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf_ambi.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf_ambi.root new file mode 100644 index 00000000000..8448a28ef8d Binary files /dev/null and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_ckf_ambi.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_seeding.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_seeding.root new file mode 100644 index 00000000000..7447c9e6b58 Binary files /dev/null and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_seeding.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_gauss_notime_hist.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_gauss_notime_hist.root new file mode 100644 index 00000000000..cb06eab079b Binary files /dev/null and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_gauss_notime_hist.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_grid_time_hist.root b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_grid_time_hist.root new file mode 100644 index 00000000000..3c6a4b94200 Binary files /dev/null and b/CI/physmon/reference/trackfinding_ttbar_pu200/performance_vertexing_amvf_grid_time_hist.root differ diff --git a/CI/physmon/reference/trackfinding_ttbar_pu200/tracksummary_ckf_hist.root b/CI/physmon/reference/trackfinding_ttbar_pu200/tracksummary_ckf_hist.root new file mode 100644 index 00000000000..a5f58e1e065 Binary files /dev/null and b/CI/physmon/reference/trackfinding_ttbar_pu200/tracksummary_ckf_hist.root differ diff --git a/CI/physmon/reference/trackfitting_gsf/performance_trackfitting.root b/CI/physmon/reference/trackfitting_gsf/performance_trackfitting.root new file mode 100644 index 00000000000..02975d42572 Binary files /dev/null and b/CI/physmon/reference/trackfitting_gsf/performance_trackfitting.root differ diff --git a/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root b/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root new file mode 100644 index 00000000000..0b1e216915e Binary files /dev/null and b/CI/physmon/reference/trackfitting_gx2f/performance_trackfitting.root differ diff --git a/CI/physmon/reference/trackfitting_kf/performance_trackfitting.root b/CI/physmon/reference/trackfitting_kf/performance_trackfitting.root new file mode 100644 index 00000000000..aade25ba5a2 Binary files /dev/null and b/CI/physmon/reference/trackfitting_kf/performance_trackfitting.root differ diff --git a/CI/physmon/reference/tracksummary_ckf_orthogonal_hist.root b/CI/physmon/reference/tracksummary_ckf_orthogonal_hist.root deleted file mode 100644 index 17568bda0d1..00000000000 Binary files a/CI/physmon/reference/tracksummary_ckf_orthogonal_hist.root and /dev/null differ diff --git a/CI/physmon/reference/tracksummary_ckf_seeded_hist.root b/CI/physmon/reference/tracksummary_ckf_seeded_hist.root deleted file mode 100644 index d94d7d61036..00000000000 Binary files a/CI/physmon/reference/tracksummary_ckf_seeded_hist.root and /dev/null differ diff --git a/CI/physmon/reference/tracksummary_ckf_truth_estimated_hist.root b/CI/physmon/reference/tracksummary_ckf_truth_estimated_hist.root deleted file mode 100644 index 45967d27ba1..00000000000 Binary files a/CI/physmon/reference/tracksummary_ckf_truth_estimated_hist.root and /dev/null differ diff --git a/CI/physmon/reference/tracksummary_ckf_truth_smeared_hist.root b/CI/physmon/reference/tracksummary_ckf_truth_smeared_hist.root deleted file mode 100644 index bcc83d6d6fa..00000000000 Binary files a/CI/physmon/reference/tracksummary_ckf_truth_smeared_hist.root and /dev/null differ diff --git a/CI/physmon/reference/tracksummary_ckf_ttbar_hist.root b/CI/physmon/reference/tracksummary_ckf_ttbar_hist.root deleted file mode 100644 index 49a8555ee7e..00000000000 Binary files a/CI/physmon/reference/tracksummary_ckf_ttbar_hist.root and /dev/null differ diff --git a/CI/physmon/summary.py b/CI/physmon/summary.py index dfd35331a55..a7de3ed74c8 100755 --- a/CI/physmon/summary.py +++ b/CI/physmon/summary.py @@ -23,12 +23,12 @@ with open(args.results) as f: reader = csv.reader(f) - for title, slug, ec in reader: + for title, html_path, ec in reader: summary.append( { "title": title, "total": ec == "0", - "path": f"{slug}.html", + "path": html_path, } ) diff --git a/CI/physmon/workflows/physmon_ckf_tracking.py b/CI/physmon/workflows/physmon_ckf_tracking.py deleted file mode 100755 index 969224f14aa..00000000000 --- a/CI/physmon/workflows/physmon_ckf_tracking.py +++ /dev/null @@ -1,269 +0,0 @@ -#!/usr/bin/env python3 - -import tempfile -from pathlib import Path -import shutil - -import acts -from acts.examples.simulation import ( - addParticleGun, - MomentumConfig, - EtaConfig, - PhiConfig, - ParticleConfig, - addFatras, - addDigitization, -) - -from acts.examples.reconstruction import ( - addSeeding, - TruthSeedRanges, - ParticleSmearingSigmas, - SeedFinderConfigArg, - SeedFinderOptionsArg, - SeedingAlgorithm, - TruthEstimatedSeedingAlgorithmConfigArg, - CkfConfig, - addCKFTracks, - addAmbiguityResolution, - AmbiguityResolutionConfig, - addVertexFitting, - VertexFinder, - TrackSelectorConfig, -) - -from physmon_common import makeSetup - -u = acts.UnitConstants - -setup = makeSetup() - - -def run_ckf_tracking(truthSmearedSeeded, truthEstimatedSeeded, label): - with tempfile.TemporaryDirectory() as temp: - s = acts.examples.Sequencer( - events=500, - numThreads=-1, - logLevel=acts.logging.INFO, - ) - - tp = Path(temp) - - for d in setup.decorators: - s.addContextDecorator(d) - - rnd = acts.examples.RandomNumbers(seed=42) - - addParticleGun( - s, - MomentumConfig(1.0 * u.GeV, 10.0 * u.GeV, transverse=True), - EtaConfig(-3.0, 3.0), - PhiConfig(0.0, 360.0 * u.degree), - ParticleConfig(4, acts.PdgParticle.eMuon, randomizeCharge=True), - vtxGen=acts.examples.GaussianVertexGenerator( - mean=acts.Vector4(0, 0, 0, 0), - stddev=acts.Vector4( - 0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 1.0 * u.ns - ), - ), - multiplicity=50, - rnd=rnd, - ) - - addFatras( - s, - setup.trackingGeometry, - setup.field, - enableInteractions=True, - rnd=rnd, - ) - - addDigitization( - s, - setup.trackingGeometry, - setup.field, - digiConfigFile=setup.digiConfig, - rnd=rnd, - ) - - addSeeding( - s, - setup.trackingGeometry, - setup.field, - TruthSeedRanges(pt=(500 * u.MeV, None), nHits=(9, None)), - ParticleSmearingSigmas( # only used by SeedingAlgorithm.TruthSmeared - # zero eveything so the CKF has a chance to find the measurements - d0=0, - d0PtA=0, - d0PtB=0, - z0=0, - z0PtA=0, - z0PtB=0, - t0=0, - phi=0, - theta=0, - ptRel=0, - ), - SeedFinderConfigArg( - r=(33 * u.mm, 200 * u.mm), - deltaR=(1 * u.mm, 60 * u.mm), - collisionRegion=(-250 * u.mm, 250 * u.mm), - z=(-2000 * u.mm, 2000 * u.mm), - maxSeedsPerSpM=1, - sigmaScattering=5, - radLengthPerSeed=0.1, - minPt=500 * u.MeV, - impactMax=3 * u.mm, - ), - SeedFinderOptionsArg(bFieldInZ=2 * u.T), - TruthEstimatedSeedingAlgorithmConfigArg(deltaR=(10.0 * u.mm, None)), - seedingAlgorithm=( - SeedingAlgorithm.TruthSmeared - if truthSmearedSeeded - else ( - SeedingAlgorithm.TruthEstimated - if truthEstimatedSeeded - else ( - SeedingAlgorithm.Default - if label == "seeded" - else SeedingAlgorithm.Orthogonal - ) - ) - ), - initialSigmas=[ - 1 * u.mm, - 1 * u.mm, - 1 * u.degree, - 1 * u.degree, - 0.1 * u.e / u.GeV, - 1 * u.ns, - ], - initialSigmaPtRel=0.01, - initialVarInflation=[1.0] * 6, - geoSelectionConfigFile=setup.geoSel, - rnd=rnd, # only used by SeedingAlgorithm.TruthSmeared - outputDirRoot=tp, - ) - - addCKFTracks( - s, - setup.trackingGeometry, - setup.field, - TrackSelectorConfig( - pt=(500 * u.MeV, None), - loc0=(-4.0 * u.mm, 4.0 * u.mm), - nMeasurementsMin=6, - maxHoles=2, - maxOutliers=2, - ), - CkfConfig( - seedDeduplication=False if truthSmearedSeeded else True, - stayOnSeed=False if truthSmearedSeeded else True, - ), - outputDirRoot=tp, - ) - - if label in ["seeded", "orthogonal"]: - addAmbiguityResolution( - s, - AmbiguityResolutionConfig( - maximumSharedHits=3, - maximumIterations=10000, - nMeasurementsMin=6, - ), - outputDirRoot=tp, - ) - - s.addAlgorithm( - acts.examples.TracksToParameters( - level=acts.logging.INFO, - inputTracks="tracks", - outputTrackParameters="trackParameters", - ) - ) - - # Choosing a seeder only has an effect on VertexFinder.AMVF. For - # VertexFinder.IVF we always use acts.VertexSeedFinder.GaussianSeeder - # (Python binding is not implemented). - # Setting useTime also only has an effect on VertexFinder.AMVF due to - # the same reason. - addVertexFitting( - s, - setup.field, - trackParameters="trackParameters", - outputProtoVertices="ivf_protovertices", - outputVertices="ivf_fittedVertices", - vertexFinder=VertexFinder.Iterative, - outputDirRoot=tp / "ivf", - ) - - addVertexFitting( - s, - setup.field, - trackParameters="trackParameters", - outputProtoVertices="amvf_protovertices", - outputVertices="amvf_fittedVertices", - seeder=acts.VertexSeedFinder.GaussianSeeder, - useTime=False, # Time seeding not implemented for the Gaussian seeder - vertexFinder=VertexFinder.AMVF, - outputDirRoot=tp / "amvf", - ) - - # Use the adaptive grid vertex seeder in combination with the AMVF - # To avoid having too many physmon cases, we only do this for the label - # "seeded" - if label == "seeded": - addVertexFitting( - s, - setup.field, - trackParameters="trackParameters", - outputProtoVertices="amvf_gridseeder_protovertices", - outputVertices="amvf_gridseeder_fittedVertices", - seeder=acts.VertexSeedFinder.AdaptiveGridSeeder, - useTime=True, - vertexFinder=VertexFinder.AMVF, - outputDirRoot=tp / "amvf_gridseeder", - ) - - s.run() - del s - - for vertexing in ["ivf", "amvf"]: - shutil.move( - tp / f"{vertexing}/performance_vertexing.root", - tp / f"performance_{vertexing}.root", - ) - - if label == "seeded": - vertexing = "amvf_gridseeder" - shutil.move( - tp / f"{vertexing}/performance_vertexing.root", - tp / f"performance_{vertexing}.root", - ) - - for stem in ( - [ - "performance_ckf", - "tracksummary_ckf", - "performance_ivf", - "performance_amvf", - ] - + (["performance_amvf_gridseeder"] if label == "seeded" else []) - + ( - ["performance_seeding", "performance_ambi"] - if label in ["seeded", "orthogonal"] - else ["performance_seeding"] if label == "truth_estimated" else [] - ) - ): - perf_file = tp / f"{stem}.root" - assert perf_file.exists(), "Performance file not found" - shutil.copy(perf_file, setup.outdir / f"{stem}_{label}.root") - - -for truthSmearedSeeded, truthEstimatedSeeded, label in [ - (True, False, "truth_smeared"), # if first is true, second is ignored - (False, True, "truth_estimated"), - (False, False, "seeded"), - (False, False, "orthogonal"), -]: - run_ckf_tracking(truthSmearedSeeded, truthEstimatedSeeded, label) diff --git a/CI/physmon/workflows/physmon_simulation.py b/CI/physmon/workflows/physmon_simulation.py index f5e9069cb2e..e2f0a71ad38 100755 --- a/CI/physmon/workflows/physmon_simulation.py +++ b/CI/physmon/workflows/physmon_simulation.py @@ -9,6 +9,7 @@ addFatras, addGeant4, ParticleSelectorConfig, + addPythia8, ) from physmon_common import makeSetup @@ -105,3 +106,39 @@ ]: assert file.exists(), "file not found" shutil.copy(file, setup.outdir / name) + +with tempfile.TemporaryDirectory() as temp: + s = acts.examples.Sequencer( + events=3, + numThreads=-1, + logLevel=acts.logging.INFO, + ) + + tp = Path(temp) + + for d in setup.decorators: + s.addContextDecorator(d) + + rnd = acts.examples.RandomNumbers(seed=42) + + addPythia8( + s, + hardProcess=["Top:qqbar2ttbar=on"], + npileup=200, + vtxGen=acts.examples.GaussianVertexGenerator( + mean=acts.Vector4(0, 0, 0, 0), + stddev=acts.Vector4(0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 5.0 * u.ns), + ), + rnd=rnd, + outputDirRoot=tp, + ) + + s.run() + del s + + for file, name in [ + (tp / "pythia8_particles.root", "particles_ttbar.root"), + (tp / "pythia8_vertices.root", "vertices_ttbar.root"), + ]: + assert file.exists(), "file not found" + shutil.copy(file, setup.outdir / name) diff --git a/CI/physmon/workflows/physmon_vertexing.py b/CI/physmon/workflows/physmon_trackfinding_1muon.py similarity index 59% rename from CI/physmon/workflows/physmon_vertexing.py rename to CI/physmon/workflows/physmon_trackfinding_1muon.py index 2486923b019..62bdbf97ee2 100755 --- a/CI/physmon/workflows/physmon_vertexing.py +++ b/CI/physmon/workflows/physmon_trackfinding_1muon.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 + import tempfile from pathlib import Path import shutil -import datetime import acts from acts.examples.simulation import ( @@ -17,15 +17,14 @@ from acts.examples.reconstruction import ( addSeeding, + TruthSeedRanges, + ParticleSmearingSigmas, SeedFinderConfigArg, SeedFinderOptionsArg, SeedingAlgorithm, + TruthEstimatedSeedingAlgorithmConfigArg, CkfConfig, addCKFTracks, - addAmbiguityResolution, - AmbiguityResolutionConfig, - addVertexFitting, - VertexFinder, TrackSelectorConfig, ) @@ -36,10 +35,10 @@ setup = makeSetup() -def run_vertexing(fitter, mu, events): +def run_ckf_tracking(label, seeding): with tempfile.TemporaryDirectory() as temp: s = acts.examples.Sequencer( - events=events, + events=10000, numThreads=-1, logLevel=acts.logging.INFO, ) @@ -54,16 +53,16 @@ def run_vertexing(fitter, mu, events): addParticleGun( s, MomentumConfig(1.0 * u.GeV, 10.0 * u.GeV, transverse=True), - EtaConfig(-3.0, 3.0), + EtaConfig(-3.0, 3.0, uniform=True), PhiConfig(0.0, 360.0 * u.degree), - ParticleConfig(4, acts.PdgParticle.eMuon, randomizeCharge=True), + ParticleConfig(1, acts.PdgParticle.eMuon, randomizeCharge=True), vtxGen=acts.examples.GaussianVertexGenerator( mean=acts.Vector4(0, 0, 0, 0), stddev=acts.Vector4( 0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 1.0 * u.ns ), ), - multiplicity=mu, + multiplicity=1, rnd=rnd, ) @@ -87,6 +86,20 @@ def run_vertexing(fitter, mu, events): s, setup.trackingGeometry, setup.field, + TruthSeedRanges(pt=(500 * u.MeV, None), nHits=(9, None)), + ParticleSmearingSigmas( # only used by SeedingAlgorithm.TruthSmeared + # zero eveything so the CKF has a chance to find the measurements + d0=0, + d0PtA=0, + d0PtB=0, + z0=0, + z0PtA=0, + z0PtB=0, + t0=0, + phi=0, + theta=0, + ptRel=0, + ), SeedFinderConfigArg( r=(33 * u.mm, 200 * u.mm), deltaR=(1 * u.mm, 60 * u.mm), @@ -99,7 +112,8 @@ def run_vertexing(fitter, mu, events): impactMax=3 * u.mm, ), SeedFinderOptionsArg(bFieldInZ=2 * u.T), - seedingAlgorithm=SeedingAlgorithm.Default, + TruthEstimatedSeedingAlgorithmConfigArg(deltaR=(10.0 * u.mm, None)), + seedingAlgorithm=seeding, initialSigmas=[ 1 * u.mm, 1 * u.mm, @@ -108,9 +122,11 @@ def run_vertexing(fitter, mu, events): 0.1 * u.e / u.GeV, 1 * u.ns, ], - initialSigmaPtRel=0.1, + initialSigmaPtRel=0.01, initialVarInflation=[1.0] * 6, geoSelectionConfigFile=setup.geoSel, + rnd=rnd, # only used by SeedingAlgorithm.TruthSmeared + outputDirRoot=tp, ) addCKFTracks( @@ -118,57 +134,42 @@ def run_vertexing(fitter, mu, events): setup.trackingGeometry, setup.field, TrackSelectorConfig( - loc0=(-4.0 * u.mm, 4.0 * u.mm), pt=(500 * u.MeV, None), + loc0=(-4.0 * u.mm, 4.0 * u.mm), nMeasurementsMin=6, maxHoles=2, maxOutliers=2, ), CkfConfig( - seedDeduplication=True, - stayOnSeed=True, - ), - ) - - addAmbiguityResolution( - s, - AmbiguityResolutionConfig( - maximumSharedHits=3, - maximumIterations=10000, - nMeasurementsMin=6, + seedDeduplication=( + True if seeding != SeedingAlgorithm.TruthSmeared else False + ), + stayOnSeed=True if seeding != SeedingAlgorithm.TruthSmeared else False, ), - ) - - addVertexFitting( - s, - setup.field, - vertexFinder=fitter, outputDirRoot=tp, ) s.run() - del s - perf_file = tp / f"performance_vertexing.root" - assert perf_file.exists(), "Performance file not found" - shutil.copy( - perf_file, - setup.outdir / f"performance_vertexing_{fitter.name}_mu{mu}.root", - ) - - -for fitter in (VertexFinder.Iterative, VertexFinder.AMVF): - for mu in (1, 10, 25, 50, 75, 100, 125, 150, 175, 200): - start = datetime.datetime.now() - - events = 5 - run_vertexing(fitter, mu, events) - - delta = datetime.datetime.now() - start - - duration = delta.total_seconds() / events - - ( - setup.outdir / f"performance_vertexing_{fitter.name}_mu{mu}_time.txt" - ).write_text(str(duration)) + for file in ( + ["performance_seeding.root"] + if seeding != SeedingAlgorithm.TruthSmeared + else [] + ) + [ + "performance_ckf.root", + "tracksummary_ckf.root", + ]: + perf_file = tp / file + assert perf_file.exists(), f"Performance file not found {perf_file}" + (setup.outdir / label).mkdir(parents=True, exist_ok=True) + shutil.copy(perf_file, setup.outdir / label / file) + + +for label, seeding in [ + ("truth_smeared", SeedingAlgorithm.TruthSmeared), + ("truth_estimated", SeedingAlgorithm.TruthEstimated), + ("seeded", SeedingAlgorithm.Default), + ("orthogonal", SeedingAlgorithm.Orthogonal), +]: + run_ckf_tracking(label, seeding) diff --git a/CI/physmon/workflows/physmon_trackfinding_4muon_50vertices.py b/CI/physmon/workflows/physmon_trackfinding_4muon_50vertices.py new file mode 100755 index 00000000000..da966a320e1 --- /dev/null +++ b/CI/physmon/workflows/physmon_trackfinding_4muon_50vertices.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python3 + +import tempfile +from pathlib import Path +import shutil + +import acts +from acts.examples.simulation import ( + addParticleGun, + MomentumConfig, + EtaConfig, + PhiConfig, + ParticleConfig, + addFatras, + addDigitization, +) +from acts.examples.reconstruction import ( + addSeeding, + TruthSeedRanges, + SeedFinderConfigArg, + SeedFinderOptionsArg, + SeedingAlgorithm, + CkfConfig, + addCKFTracks, + addAmbiguityResolution, + AmbiguityResolutionConfig, + addVertexFitting, + VertexFinder, + TrackSelectorConfig, +) + +from physmon_common import makeSetup + +u = acts.UnitConstants + +setup = makeSetup() + + +with tempfile.TemporaryDirectory() as temp: + s = acts.examples.Sequencer( + events=3, + numThreads=-1, + logLevel=acts.logging.INFO, + ) + + tp = Path(temp) + + for d in setup.decorators: + s.addContextDecorator(d) + + rnd = acts.examples.RandomNumbers(seed=42) + + addParticleGun( + s, + MomentumConfig(1.0 * u.GeV, 10.0 * u.GeV, transverse=True), + EtaConfig(-3.0, 3.0, uniform=True), + PhiConfig(0.0, 360.0 * u.degree), + ParticleConfig(10, acts.PdgParticle.eMuon, randomizeCharge=True), + vtxGen=acts.examples.GaussianVertexGenerator( + mean=acts.Vector4(0, 0, 0, 0), + stddev=acts.Vector4(0.0125 * u.mm, 0.0125 * u.mm, 55.5 * u.mm, 1.0 * u.ns), + ), + multiplicity=50, + rnd=rnd, + ) + + addFatras( + s, + setup.trackingGeometry, + setup.field, + rnd=rnd, + ) + + addDigitization( + s, + setup.trackingGeometry, + setup.field, + digiConfigFile=setup.digiConfig, + rnd=rnd, + ) + + addSeeding( + s, + setup.trackingGeometry, + setup.field, + TruthSeedRanges(pt=(500.0 * u.MeV, None), nHits=(9, None)), + SeedFinderConfigArg( + r=(33 * u.mm, 200 * u.mm), + deltaR=(1 * u.mm, 60 * u.mm), + collisionRegion=(-250 * u.mm, 250 * u.mm), + z=(-2000 * u.mm, 2000 * u.mm), + maxSeedsPerSpM=1, + sigmaScattering=5, + radLengthPerSeed=0.1, + minPt=500 * u.MeV, + impactMax=3 * u.mm, + ), + SeedFinderOptionsArg(bFieldInZ=2 * u.T, beamPos=(0.0, 0.0)), + seedingAlgorithm=SeedingAlgorithm.Default, + initialSigmas=[ + 1 * u.mm, + 1 * u.mm, + 1 * u.degree, + 1 * u.degree, + 0.1 * u.e / u.GeV, + 1 * u.ns, + ], + initialSigmaPtRel=0.01, + initialVarInflation=[1.0] * 6, + geoSelectionConfigFile=setup.geoSel, + outputDirRoot=tp, + ) + + addCKFTracks( + s, + setup.trackingGeometry, + setup.field, + TrackSelectorConfig( + pt=(500 * u.MeV, None), + loc0=(-4.0 * u.mm, 4.0 * u.mm), + nMeasurementsMin=6, + maxHoles=2, + maxOutliers=2, + ), + CkfConfig( + seedDeduplication=True, + stayOnSeed=True, + ), + outputDirRoot=tp, + ) + + addAmbiguityResolution( + s, + AmbiguityResolutionConfig( + maximumSharedHits=3, + maximumIterations=100000, + nMeasurementsMin=6, + ), + outputDirRoot=tp, + ) + + s.addAlgorithm( + acts.examples.TracksToParameters( + level=acts.logging.INFO, + inputTracks="tracks", + outputTrackParameters="trackParameters", + ) + ) + + # Choosing a seeder only has an effect on VertexFinder.AMVF. For + # VertexFinder.IVF we always use acts.VertexSeedFinder.GaussianSeeder + # (Python binding is not implemented). + # Setting useTime also only has an effect on VertexFinder.AMVF due to + # the same reason. + addVertexFitting( + s, + setup.field, + trackParameters="trackParameters", + outputProtoVertices="ivf_notime_protovertices", + outputVertices="ivf_notime_fittedVertices", + vertexFinder=VertexFinder.Iterative, + outputDirRoot=tp / "ivf_notime", + ) + + addVertexFitting( + s, + setup.field, + trackParameters="trackParameters", + outputProtoVertices="amvf_gauss_notime_protovertices", + outputVertices="amvf_gauss_notime_fittedVertices", + seeder=acts.VertexSeedFinder.GaussianSeeder, + useTime=False, # Time seeding not implemented for the Gaussian seeder + vertexFinder=VertexFinder.AMVF, + outputDirRoot=tp / "amvf_gauss_notime", + ) + + addVertexFitting( + s, + setup.field, + trackParameters="trackParameters", + outputProtoVertices="amvf_grid_time_protovertices", + outputVertices="amvf_grid_time_fittedVertices", + seeder=acts.VertexSeedFinder.AdaptiveGridSeeder, + useTime=True, + vertexFinder=VertexFinder.AMVF, + outputDirRoot=tp / "amvf_grid_time", + ) + + s.run() + del s + + shutil.move( + tp / "performance_ambi.root", + tp / "performance_ckf_ambi.root", + ) + for vertexing in ["ivf_notime", "amvf_gauss_notime", "amvf_grid_time"]: + shutil.move( + tp / f"{vertexing}/performance_vertexing.root", + tp / f"performance_vertexing_{vertexing}.root", + ) + + for file in [ + "performance_seeding.root", + "tracksummary_ckf.root", + "performance_ckf.root", + "performance_ckf_ambi.root", + "performance_vertexing_ivf_notime.root", + "performance_vertexing_amvf_gauss_notime.root", + "performance_vertexing_amvf_grid_time.root", + ]: + perf_file = tp / file + assert perf_file.exists(), f"Performance file not found {perf_file}" + shutil.copy(perf_file, setup.outdir / file) diff --git a/CI/physmon/workflows/physmon_track_finding_ttbar.py b/CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py similarity index 74% rename from CI/physmon/workflows/physmon_track_finding_ttbar.py rename to CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py index ad159a36380..b855e313745 100755 --- a/CI/physmon/workflows/physmon_track_finding_ttbar.py +++ b/CI/physmon/workflows/physmon_trackfinding_ttbar_pu200.py @@ -91,6 +91,16 @@ ), SeedFinderOptionsArg(bFieldInZ=2 * u.T, beamPos=(0.0, 0.0)), seedingAlgorithm=SeedingAlgorithm.Default, + initialSigmas=[ + 1 * u.mm, + 1 * u.mm, + 1 * u.degree, + 1 * u.degree, + 0.1 * u.e / u.GeV, + 1 * u.ns, + ], + initialSigmaPtRel=0.01, + initialVarInflation=[1.0] * 6, geoSelectionConfigFile=setup.geoSel, outputDirRoot=tp, ) @@ -136,11 +146,11 @@ setup.field, tracks="tracks", trackParameters="trackParameters", - outputProtoVertices="amvf_protovertices", - outputVertices="amvf_fittedVertices", + outputProtoVertices="amvf_gauss_notime_protovertices", + outputVertices="amvf_gauss_notime_fittedVertices", seeder=acts.VertexSeedFinder.GaussianSeeder, vertexFinder=VertexFinder.AMVF, - outputDirRoot=tp / "amvf", + outputDirRoot=tp / "amvf_gauss_notime", ) addVertexFitting( @@ -148,33 +158,35 @@ setup.field, tracks="tracks", trackParameters="trackParameters", - outputProtoVertices="amvf_gridseeder_protovertices", - outputVertices="amvf_gridseeder_fittedVertices", + outputProtoVertices="amvf_grid_time_protovertices", + outputVertices="amvf_grid_time_fittedVertices", seeder=acts.VertexSeedFinder.AdaptiveGridSeeder, useTime=True, vertexFinder=VertexFinder.AMVF, - outputDirRoot=tp / "amvf_gridseeder", + outputDirRoot=tp / "amvf_grid_time", ) s.run() del s - for vertexing in ["amvf", "amvf_gridseeder"]: + shutil.move( + tp / "performance_ambi.root", + tp / "performance_ckf_ambi.root", + ) + for vertexing in ["amvf_gauss_notime", "amvf_grid_time"]: shutil.move( tp / f"{vertexing}/performance_vertexing.root", - tp / f"performance_{vertexing}.root", + tp / f"performance_vertexing_{vertexing}.root", ) - for stem in [ - "performance_ckf", - "tracksummary_ckf", - "performance_amvf", - "performance_amvf_gridseeder", - "performance_seeding", - "performance_ambi", - "pythia8_particles", - "pythia8_vertices", + for file in [ + "performance_seeding.root", + "tracksummary_ckf.root", + "performance_ckf.root", + "performance_ckf_ambi.root", + "performance_vertexing_amvf_gauss_notime.root", + "performance_vertexing_amvf_grid_time.root", ]: - perf_file = tp / f"{stem}.root" - assert perf_file.exists(), "Performance file not found" - shutil.copy(perf_file, setup.outdir / f"{stem}_ttbar.root") + perf_file = tp / file + assert perf_file.exists(), f"Performance file not found {perf_file}" + shutil.copy(perf_file, setup.outdir / file) diff --git a/CI/physmon/workflows/physmon_truth_tracking_gsf.py b/CI/physmon/workflows/physmon_trackfitting_gsf.py similarity index 89% rename from CI/physmon/workflows/physmon_truth_tracking_gsf.py rename to CI/physmon/workflows/physmon_trackfitting_gsf.py index d56cd603f23..34eb0b5a99a 100755 --- a/CI/physmon/workflows/physmon_truth_tracking_gsf.py +++ b/CI/physmon/workflows/physmon_trackfitting_gsf.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 + import tempfile from pathlib import Path import shutil @@ -31,4 +32,4 @@ perf_file = tp / "performance_gsf.root" assert perf_file.exists(), "Performance file not found" - shutil.copy(perf_file, setup.outdir / "performance_gsf.root") + shutil.copy(perf_file, setup.outdir / "performance_trackfitting.root") diff --git a/CI/physmon/workflows/physmon_truth_tracking_gx2f.py b/CI/physmon/workflows/physmon_trackfitting_gx2f.py similarity index 90% rename from CI/physmon/workflows/physmon_truth_tracking_gx2f.py rename to CI/physmon/workflows/physmon_trackfitting_gx2f.py index 019fc6b5114..2644e291757 100755 --- a/CI/physmon/workflows/physmon_truth_tracking_gx2f.py +++ b/CI/physmon/workflows/physmon_trackfitting_gx2f.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 + import tempfile from pathlib import Path import shutil @@ -31,4 +32,4 @@ perf_file = tp / "performance_gx2f.root" assert perf_file.exists(), "Performance file not found" - shutil.copy(perf_file, setup.outdir / "performance_gx2f.root") + shutil.copy(perf_file, setup.outdir / "performance_trackfitting.root") diff --git a/CI/physmon/workflows/physmon_truth_tracking_kalman.py b/CI/physmon/workflows/physmon_trackfitting_kf.py similarity index 83% rename from CI/physmon/workflows/physmon_truth_tracking_kalman.py rename to CI/physmon/workflows/physmon_trackfitting_kf.py index 712dca6ac43..1bb09d1aa57 100755 --- a/CI/physmon/workflows/physmon_truth_tracking_kalman.py +++ b/CI/physmon/workflows/physmon_trackfitting_kf.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 + import tempfile from pathlib import Path import shutil @@ -29,6 +30,6 @@ s.run() del s - perf_file = tp / "performance_track_fitter.root" + perf_file = tp / "performance_kf.root" assert perf_file.exists(), "Performance file not found" - shutil.copy(perf_file, setup.outdir / "performance_truth_tracking.root") + shutil.copy(perf_file, setup.outdir / "performance_trackfitting.root") diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f550182648..a5e41889246 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,6 @@ option(ACTS_BUILD_PLUGIN_ONNX "Build ONNX plugin" OFF) option(ACTS_USE_SYSTEM_COVFIE "Use a system-provided covfie installation" ${ACTS_USE_SYSTEM_LIBS}) option(ACTS_USE_SYSTEM_DETRAY "Use a system-provided detray installation" ${ACTS_USE_SYSTEM_LIBS}) option(ACTS_USE_SYSTEM_TRACCC "Use a system-provided traccc installation" ${ACTS_USE_SYSTEM_LIBS}) -option(ACTS_USE_SYSTEM_DFELIBS "Use a system-provided dfelibs installation" ${ACTS_USE_SYSTEM_LIBS}) option(ACTS_USE_SYSTEM_VECMEM "Use a system-provided vecmem installation" ${ACTS_USE_SYSTEM_LIBS}) option(ACTS_USE_SYSTEM_ALGEBRAPLUGINS "Use a system-provided algebra-plugins installation" ${ACTS_USE_SYSTEM_LIBS}) option(ACTS_BUILD_PLUGIN_TGEO "Build TGeo plugin" OFF) @@ -254,11 +253,6 @@ if (ACTS_SETUP_EIGEN3) endif() endif() -if (ACTS_USE_SYSTEM_DFELIBS) - find_package(dfelibs ${_acts_dfelibs_version} REQUIRED) -else() - add_subdirectory(thirdparty/dfelibs) -endif() find_package(Filesystem REQUIRED) diff --git a/Core/include/Acts/EventData/MultiTrajectory.hpp b/Core/include/Acts/EventData/MultiTrajectory.hpp index 9a148efeb9d..b914556b77b 100644 --- a/Core/include/Acts/EventData/MultiTrajectory.hpp +++ b/Core/include/Acts/EventData/MultiTrajectory.hpp @@ -642,9 +642,12 @@ class MultiTrajectory { self().allocateCalibrated_impl(istate, measdim); } - void setUncalibratedSourceLink(IndexType istate, - SourceLink sourceLink) requires(!ReadOnly) { - self().setUncalibratedSourceLink_impl(istate, std::move(sourceLink)); + // This function will move to an rvalue reference in the next major version + template + void setUncalibratedSourceLink( + IndexType istate, source_link_t&& sourceLink) requires(!ReadOnly) { + self().setUncalibratedSourceLink_impl( + istate, std::forward(sourceLink)); } SourceLink getUncalibratedSourceLink(IndexType istate) const { diff --git a/Core/include/Acts/EventData/MultiTrajectoryBackendConcept.hpp b/Core/include/Acts/EventData/MultiTrajectoryBackendConcept.hpp index f93dc997e9d..a3c068b7269 100644 --- a/Core/include/Acts/EventData/MultiTrajectoryBackendConcept.hpp +++ b/Core/include/Acts/EventData/MultiTrajectoryBackendConcept.hpp @@ -130,7 +130,7 @@ concept MutableMultiTrajectoryBackend = CommonMultiTrajectoryBackend && {v.allocateCalibrated_impl(istate, dim)}; - {v.setUncalibratedSourceLink_impl(istate, sl)}; + {v.setUncalibratedSourceLink_impl(istate, std::move(sl))}; {v.setReferenceSurface_impl(istate, surface)}; diff --git a/Core/include/Acts/EventData/SourceLink.hpp b/Core/include/Acts/EventData/SourceLink.hpp index 7ba41fce008..4d26b7589c9 100644 --- a/Core/include/Acts/EventData/SourceLink.hpp +++ b/Core/include/Acts/EventData/SourceLink.hpp @@ -39,15 +39,9 @@ class SourceLink final { /// @param upstream The upstream source link to store template , SourceLink>>> - explicit SourceLink(T&& upstream) { + explicit SourceLink(T&& upstream) : m_upstream(std::forward(upstream)) { static_assert(!std::is_same_v, SourceLink>, "Cannot wrap SourceLink in SourceLink"); - - if constexpr (std::is_same_v>) { - m_upstream = any_type{std::forward(upstream)}; - } else { - m_upstream = any_type{static_cast>(upstream)}; - } } /// Concrete source link class getter diff --git a/Core/include/Acts/EventData/TrackStateProxy.hpp b/Core/include/Acts/EventData/TrackStateProxy.hpp index f0ebe42cdd9..eb565de87ca 100644 --- a/Core/include/Acts/EventData/TrackStateProxy.hpp +++ b/Core/include/Acts/EventData/TrackStateProxy.hpp @@ -676,10 +676,23 @@ class TrackStateProxy { /// @return The uncalibrated measurement source link SourceLink getUncalibratedSourceLink() const; + // This function will move to an rvalue reference in the next major version /// Set an uncalibrated source link /// @param sourceLink The uncalibrated source link to set - void setUncalibratedSourceLink(SourceLink sourceLink) requires(!ReadOnly) { - m_traj->setUncalibratedSourceLink(m_istate, std::move(sourceLink)); + template + void setUncalibratedSourceLink(source_link_t&& sourceLink) requires( + !ReadOnly) { + m_traj->setUncalibratedSourceLink(m_istate, + std::forward(sourceLink)); + } + + /// Set an uncalibrated source link + /// @param sourceLink The uncalibrated source link to set + /// @note Use the overload with an rvalue reference, this + /// overload will be removed ith the next major version + void setUncalibratedSourceLink(const SourceLink& sourceLink) requires( + !ReadOnly) { + m_traj->setUncalibratedSourceLink(m_istate, SourceLink{sourceLink}); } /// Check if the point has an associated uncalibrated measurement. diff --git a/Core/include/Acts/EventData/VectorMultiTrajectory.hpp b/Core/include/Acts/EventData/VectorMultiTrajectory.hpp index 97511817cca..fa6d06590bc 100644 --- a/Core/include/Acts/EventData/VectorMultiTrajectory.hpp +++ b/Core/include/Acts/EventData/VectorMultiTrajectory.hpp @@ -484,7 +484,8 @@ class VectorMultiTrajectory final m_measCov.resize(m_measCov.size() + measdim * measdim); } - void setUncalibratedSourceLink_impl(IndexType istate, SourceLink sourceLink) { + void setUncalibratedSourceLink_impl(IndexType istate, + SourceLink&& sourceLink) { m_sourceLinks[m_index[istate].iuncalibrated] = std::move(sourceLink); } diff --git a/Core/include/Acts/EventData/detail/TestSourceLink.hpp b/Core/include/Acts/EventData/detail/TestSourceLink.hpp index d215867036c..d0bedcce0ef 100644 --- a/Core/include/Acts/EventData/detail/TestSourceLink.hpp +++ b/Core/include/Acts/EventData/detail/TestSourceLink.hpp @@ -132,7 +132,7 @@ void testSourceLinkCalibratorReturn( typename trajectory_t::TrackStateProxy trackState) { TestSourceLink sl = sourceLink.template get(); - trackState.setUncalibratedSourceLink(sourceLink); + trackState.setUncalibratedSourceLink(SourceLink{sourceLink}); if ((sl.indices[0] != Acts::eBoundSize) && (sl.indices[1] != Acts::eBoundSize)) { diff --git a/Core/include/Acts/Surfaces/CylinderSurface.hpp b/Core/include/Acts/Surfaces/CylinderSurface.hpp index b7daa6c3f08..b7b1cc34fbd 100644 --- a/Core/include/Acts/Surfaces/CylinderSurface.hpp +++ b/Core/include/Acts/Surfaces/CylinderSurface.hpp @@ -252,14 +252,16 @@ class CylinderSurface : public RegularSurface { /// @image html Cylinder_Merging.svg /// @note The surfaces need to be *compatible*, i.e. have cylinder bounds /// that align, and have the same radius - /// @param gctx The current geometry context object, e.g. alignment /// @param other The other cylinder surface to merge with /// @param direction The binning direction: either @c binZ or @c binRPhi + /// @param externalRotation If true, any phi rotation is done in the transform /// @param logger The logger to use - /// @return The merged cylinder surface - std::shared_ptr mergedWith( - const GeometryContext& gctx, const CylinderSurface& other, - BinningValue direction, const Logger& logger = getDummyLogger()) const; + /// @return The merged cylinder surface and a boolean indicating if surfaces are reversed + /// @note The returned boolean is `false` if `this` is *left* or + /// *counter-clockwise* of @p other, and `true` if not. + std::pair, bool> mergedWith( + const CylinderSurface& other, BinningValue direction, + bool externalRotation, const Logger& logger = getDummyLogger()) const; protected: std::shared_ptr m_bounds; //!< bounds (shared) diff --git a/Core/include/Acts/Surfaces/DiscSurface.hpp b/Core/include/Acts/Surfaces/DiscSurface.hpp index 4649516cc8c..819d3d3d106 100644 --- a/Core/include/Acts/Surfaces/DiscSurface.hpp +++ b/Core/include/Acts/Surfaces/DiscSurface.hpp @@ -335,14 +335,16 @@ class DiscSurface : public RegularSurface { /// @image html Disc_Merging.svg /// @note The surfaces need to be *compatible*, i.e. have disc bounds /// that align - /// @param gctx The current geometry context object, e.g. alignment /// @param other The other disc surface to merge with /// @param direction The binning direction: either @c binR or @c binPhi + /// @param externalRotation If true, any phi rotation is done in the transform /// @param logger The logger to use - /// @return The merged disc surface - std::shared_ptr mergedWith( - const GeometryContext& gctx, const DiscSurface& other, - BinningValue direction, const Logger& logger = getDummyLogger()) const; + /// @return The merged disc surface and a boolean indicating if surfaces are reversed + /// @note The returned boolean is `false` if `this` is *left* or + /// *counter-clockwise* of @p other, and `true` if not. + std::pair, bool> mergedWith( + const DiscSurface& other, BinningValue direction, bool externalRotation, + const Logger& logger = getDummyLogger()) const; protected: std::shared_ptr m_bounds; ///< bounds (shared) diff --git a/Core/include/Acts/Surfaces/detail/MergeHelper.hpp b/Core/include/Acts/Surfaces/detail/MergeHelper.hpp index 08bbd915148..33b2c53d709 100644 --- a/Core/include/Acts/Surfaces/detail/MergeHelper.hpp +++ b/Core/include/Acts/Surfaces/detail/MergeHelper.hpp @@ -23,7 +23,7 @@ namespace Acts::detail { /// a half phi sector in the range [0,pi). The two /// ranges need to line up, i.e. that one of the sector /// ends exactly where the other one starts. -std::pair mergedPhiSector( +std::tuple mergedPhiSector( ActsScalar hlPhi1, ActsScalar avgPhi1, ActsScalar hlPhi2, ActsScalar avgPhi2, const Logger& logger = getDummyLogger(), ActsScalar tolerance = s_onSurfaceTolerance); diff --git a/Core/include/Acts/Utilities/Any.hpp b/Core/include/Acts/Utilities/Any.hpp index 0eac36cf687..3f3383522af 100644 --- a/Core/include/Acts/Utilities/Any.hpp +++ b/Core/include/Acts/Utilities/Any.hpp @@ -12,7 +12,6 @@ #include #include #include -#include #include // #define _ACTS_ANY_ENABLE_VERBOSE @@ -130,6 +129,7 @@ class AnyBase : public AnyBaseAll { } else { // too large, heap allocate U* heap = new U(std::forward(args)...); + _ACTS_ANY_DEBUG("Allocate type: " << typeid(U).name() << " at " << heap); _ACTS_ANY_TRACK_ALLOCATION(T, heap); setDataPtr(heap); } @@ -335,6 +335,7 @@ class AnyBase : public AnyBaseAll { void destroy() { _ACTS_ANY_VERBOSE("Destructor this=" << this << " handler: " << m_handler); if (m_handler != nullptr && m_handler->destroy != nullptr) { + _ACTS_ANY_VERBOSE("Non-trivial destruction"); m_handler->destroy(dataPtr()); } m_handler = nullptr; @@ -356,6 +357,7 @@ class AnyBase : public AnyBaseAll { } if (m_handler->moveConstruct == nullptr) { + _ACTS_ANY_VERBOSE("Trivially move construct"); // trivially move constructible m_data = std::move(fromAny.m_data); } else { @@ -381,6 +383,7 @@ class AnyBase : public AnyBaseAll { } if (m_handler->move == nullptr) { + _ACTS_ANY_VERBOSE("Trivially move"); // trivially movable m_data = std::move(fromAny.m_data); } else { @@ -397,6 +400,7 @@ class AnyBase : public AnyBaseAll { const void* from = fromAny.dataPtr(); if (m_handler->copyConstruct == nullptr) { + _ACTS_ANY_VERBOSE("Trivially copy construct"); // trivially copy constructible m_data = fromAny.m_data; } else { @@ -418,6 +422,7 @@ class AnyBase : public AnyBaseAll { const void* from = fromAny.dataPtr(); if (m_handler->copy == nullptr) { + _ACTS_ANY_VERBOSE("Trivially copy"); // trivially copyable m_data = fromAny.m_data; } else { diff --git a/Core/include/Acts/Utilities/Axis.hpp b/Core/include/Acts/Utilities/Axis.hpp index fd595a44660..037d8c37b8f 100644 --- a/Core/include/Acts/Utilities/Axis.hpp +++ b/Core/include/Acts/Utilities/Axis.hpp @@ -392,6 +392,17 @@ class Axis final : public IAxis { return binEdges; } + friend std::ostream& operator<<(std::ostream& os, const Axis& axis) { + os << "Axis("; + os << axis.m_min << ", "; + os << axis.m_max << ", "; + os << axis.m_bins << ")"; + return os; + } + + protected: + void toStream(std::ostream& os) const override { os << *this; } + private: /// minimum of binning range ActsScalar m_min{}; @@ -695,6 +706,19 @@ class Axis final : public IAxis { /// @return Vector which contains the bin edges std::vector getBinEdges() const override { return m_binEdges; } + friend std::ostream& operator<<(std::ostream& os, const Axis& axis) { + os << "Axis("; + os << axis.m_binEdges.front(); + for (std::size_t i = 1; i < axis.m_binEdges.size(); i++) { + os << ", " << axis.m_binEdges[i]; + } + os << ")"; + return os; + } + + protected: + void toStream(std::ostream& os) const override { os << *this; } + private: /// vector of bin edges (sorted in ascending order) std::vector m_binEdges; diff --git a/Core/include/Acts/Utilities/Grid.hpp b/Core/include/Acts/Utilities/Grid.hpp index feb6bbaa15f..66069820fdb 100644 --- a/Core/include/Acts/Utilities/Grid.hpp +++ b/Core/include/Acts/Utilities/Grid.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include namespace Acts { @@ -39,6 +40,26 @@ class IGrid { /// Get a dynamically sized vector of axis objects for inspection /// @return a vector of axis pointers virtual boost::container::small_vector axes() const = 0; + + /// Helper to print out the grid + /// @param os the output stream + /// @param grid the grid to print + /// @return the output stream + friend std::ostream& operator<<(std::ostream& os, const IGrid& grid) { + grid.toStream(os); + return os; + } + + friend bool operator==(const IGrid& lhs, const IGrid& rhs) { + auto lhsAxes = lhs.axes(); + auto rhsAxes = rhs.axes(); + return lhsAxes.size() == rhsAxes.size() && + std::equal(lhsAxes.begin(), lhsAxes.end(), rhsAxes.begin(), + [](const IAxis* a, const IAxis* b) { return *a == *b; }); + } + + protected: + virtual void toStream(std::ostream& os) const = 0; }; /// @brief class for describing a regular multi-dimensional grid @@ -583,6 +604,11 @@ class Grid final : public IGrid { return local_iterator_t(*this, std::move(endline), navigator); } + protected: + void toStream(std::ostream& os) const override { + printAxes(os, std::make_index_sequence()); + } + private: /// set of axis defining the multi-dimensional grid std::tuple m_axes; @@ -596,6 +622,18 @@ class Grid final : public IGrid { const index_t& localBins) const { return detail::grid_helper::closestPointsIndices(localBins, m_axes); } + + template + void printAxes(std::ostream& os, std::index_sequence /*s*/) const { + auto printOne = [&os, this]( + std::integral_constant) { + if constexpr (index > 0) { + os << ", "; + } + os << std::get(m_axes); + }; + (printOne(std::integral_constant()), ...); + } }; template diff --git a/Core/include/Acts/Utilities/IAxis.hpp b/Core/include/Acts/Utilities/IAxis.hpp index 9c21912ad09..f61e3310d3b 100644 --- a/Core/include/Acts/Utilities/IAxis.hpp +++ b/Core/include/Acts/Utilities/IAxis.hpp @@ -11,6 +11,7 @@ #include "Acts/Definitions/Algebra.hpp" #include "Acts/Utilities/AxisFwd.hpp" +#include #include namespace Acts { @@ -56,5 +57,66 @@ class IAxis { /// /// @return total number of bins (excluding under-/overflow bins) virtual std::size_t getNBins() const = 0; + + /// Helper function that dispatches from the @c IAxis base class + /// to a concrete axis type. It will call the provided @p callable + /// with a const reference to the concrete axis type. + /// @tparam callable_t the callable type + /// @param callable the callable object + template + decltype(auto) visit(const callable_t& callable) const { + auto switchOnType = + [this, &callable](AxisBoundaryTypeTag) { + switch (getType()) { + using enum AxisType; + case Equidistant: + return callable( + dynamic_cast&>(*this)); + case Variable: + return callable( + dynamic_cast&>(*this)); + } + }; + + switch (getBoundaryType()) { + using enum AxisBoundaryType; + case Open: + return switchOnType(AxisOpen); + case Bound: + return switchOnType(AxisBound); + case Closed: + return switchOnType(AxisClosed); + } + } + + /// Check if two axes are equal + /// @param lhs first axis + /// @param rhs second axis + /// @return true if the axes are equal + friend bool operator==(const IAxis& lhs, const IAxis& rhs) { + return lhs.getType() == rhs.getType() && + lhs.getBoundaryType() == rhs.getBoundaryType() && + lhs.getMin() == rhs.getMin() && lhs.getMax() == rhs.getMax() && + lhs.getNBins() == rhs.getNBins() && + lhs.getBinEdges() == rhs.getBinEdges(); + } + + /// Output stream operator + /// @param os output stream + /// @param axis the axis to be printed + /// @return the output stream + friend std::ostream& operator<<(std::ostream& os, const IAxis& axis) { + axis.toStream(os); + return os; + } + + protected: + /// Dispatch to the correct stream operator + /// @param os output stream + virtual void toStream(std::ostream& os) const = 0; }; + +template +concept AxisConcept = std::derived_from; + } // namespace Acts diff --git a/Core/src/Surfaces/CylinderSurface.cpp b/Core/src/Surfaces/CylinderSurface.cpp index 7920645d074..b53e6bf1b7d 100644 --- a/Core/src/Surfaces/CylinderSurface.cpp +++ b/Core/src/Surfaces/CylinderSurface.cpp @@ -368,20 +368,32 @@ Acts::CylinderSurface::localCartesianToBoundLocalDerivative( return loc3DToLocBound; } -std::shared_ptr Acts::CylinderSurface::mergedWith( - const GeometryContext& gctx, const CylinderSurface& other, - BinningValue direction, const Logger& logger) const { +std::pair, bool> +Acts::CylinderSurface::mergedWith(const CylinderSurface& other, + BinningValue direction, bool externalRotation, + const Logger& logger) const { using namespace Acts::UnitLiterals; ACTS_DEBUG("Merging cylinder surfaces in " << binningValueName(direction) << " direction"); - Transform3 otherLocal = transform(gctx).inverse() * other.transform(gctx); + if (m_associatedDetElement != nullptr || + other.m_associatedDetElement != nullptr) { + throw SurfaceMergingException(getSharedPtr(), other.getSharedPtr(), + "CylinderSurface::merge: surfaces are " + "associated with a detector element"); + } + + assert(m_transform != nullptr && other.m_transform != nullptr); + + Transform3 otherLocal = m_transform->inverse() * *other.m_transform; constexpr auto tolerance = s_onSurfaceTolerance; // surface cannot have any relative rotation - if (!otherLocal.linear().isApprox(RotationMatrix3::Identity())) { + + if (std::abs(otherLocal.linear().col(eX)[eZ]) >= tolerance || + std::abs(otherLocal.linear().col(eY)[eZ]) >= tolerance) { ACTS_ERROR("CylinderSurface::merge: surfaces have relative rotation"); throw SurfaceMergingException( getSharedPtr(), other.getSharedPtr(), @@ -436,17 +448,31 @@ std::shared_ptr Acts::CylinderSurface::mergedWith( "CylinderSurface::merge: surfaces have relative translation in x/y"); } + ActsScalar hlZ = bounds().get(CylinderBounds::eHalfLengthZ); + ActsScalar minZ = -hlZ; + ActsScalar maxZ = hlZ; + + ActsScalar zShift = translation[2]; + ActsScalar otherHlZ = other.bounds().get(CylinderBounds::eHalfLengthZ); + ActsScalar otherMinZ = -otherHlZ + zShift; + ActsScalar otherMaxZ = otherHlZ + zShift; + + ActsScalar hlPhi = bounds().get(CylinderBounds::eHalfPhiSector); + ActsScalar avgPhi = bounds().get(CylinderBounds::eAveragePhi); + + ActsScalar otherHlPhi = other.bounds().get(CylinderBounds::eHalfPhiSector); + ActsScalar otherAvgPhi = other.bounds().get(CylinderBounds::eAveragePhi); + if (direction == Acts::BinningValue::binZ) { // z shift must match the bounds - ActsScalar hlZ = bounds().get(CylinderBounds::eHalfLengthZ); - ActsScalar minZ = -hlZ; - ActsScalar maxZ = hlZ; - - ActsScalar zShift = translation[2]; - ActsScalar otherHlZ = other.bounds().get(CylinderBounds::eHalfLengthZ); - ActsScalar otherMinZ = -otherHlZ + zShift; - ActsScalar otherMaxZ = otherHlZ + zShift; + if (std::abs(otherLocal.linear().col(eY)[eX]) >= tolerance && + (!bounds().coversFullAzimuth() || + !other.bounds().coversFullAzimuth())) { + throw SurfaceMergingException(getSharedPtr(), other.getSharedPtr(), + "CylinderSurface::merge: surfaces have " + "relative rotation in z and phi sector"); + } ACTS_VERBOSE("this: [" << minZ << ", " << maxZ << "] ~> " << (minZ + maxZ) / 2.0 << " +- " << hlZ); @@ -455,7 +481,6 @@ std::shared_ptr Acts::CylinderSurface::mergedWith( ACTS_VERBOSE("other: [" << otherMinZ << ", " << otherMaxZ << "] ~> " << (otherMinZ + otherMaxZ) / 2.0 << " +- " << otherHlZ); - if (std::abs(maxZ - otherMinZ) > tolerance && std::abs(minZ - otherMaxZ) > tolerance) { ACTS_ERROR("CylinderSurface::merge: surfaces have incompatible z bounds"); @@ -464,6 +489,12 @@ std::shared_ptr Acts::CylinderSurface::mergedWith( "CylinderSurface::merge: surfaces have incompatible z bounds"); } + if (hlPhi != otherHlPhi || avgPhi != otherAvgPhi) { + throw SurfaceMergingException(getSharedPtr(), other.getSharedPtr(), + "CylinderSurface::merge: surfaces have " + "different phi sectors"); + } + ActsScalar newMaxZ = std::max(maxZ, otherMaxZ); ActsScalar newMinZ = std::min(minZ, otherMinZ); ActsScalar newHlZ = (newMaxZ - newMinZ) / 2.0; @@ -471,12 +502,13 @@ std::shared_ptr Acts::CylinderSurface::mergedWith( ACTS_VERBOSE("merged: [" << newMinZ << ", " << newMaxZ << "] ~> " << newMidZ << " +- " << newHlZ); - auto newBounds = std::make_shared(r, newHlZ); + auto newBounds = std::make_shared(r, newHlZ, hlPhi, avgPhi); Transform3 newTransform = - transform(gctx) * Translation3{Vector3::UnitZ() * newMidZ}; + *m_transform * Translation3{Vector3::UnitZ() * newMidZ}; - return Surface::makeShared(newTransform, newBounds); + return {Surface::makeShared(newTransform, newBounds), + zShift < 0}; } else if (direction == Acts::BinningValue::binRPhi) { // no z shift is allowed @@ -490,20 +522,47 @@ std::shared_ptr Acts::CylinderSurface::mergedWith( "rPhi merging"); } - ActsScalar hlPhi = bounds().get(CylinderBounds::eHalfPhiSector); - ActsScalar avgPhi = bounds().get(CylinderBounds::eAveragePhi); + if (hlZ != otherHlZ) { + throw SurfaceMergingException(getSharedPtr(), other.getSharedPtr(), + "CylinderSurface::merge: surfaces have " + "different z bounds"); + } - ActsScalar otherHlPhi = other.bounds().get(CylinderBounds::eHalfPhiSector); - ActsScalar otherAvgPhi = other.bounds().get(CylinderBounds::eAveragePhi); + // Figure out signed relative rotation + Vector2 rotatedX = otherLocal.linear().col(eX).head<2>(); + ActsScalar zrotation = std::atan2(rotatedX[1], rotatedX[0]); + + ACTS_VERBOSE("this: [" << avgPhi / 1_degree << " +- " << hlPhi / 1_degree + << "]"); + ACTS_VERBOSE("other: [" << otherAvgPhi / 1_degree << " +- " + << otherHlPhi / 1_degree << "]"); + + ACTS_VERBOSE("Relative rotation around local z: " << zrotation / 1_degree); + + ActsScalar prevOtherAvgPhi = otherAvgPhi; + otherAvgPhi = detail::radian_sym(otherAvgPhi + zrotation); + ACTS_VERBOSE("~> local other average phi: " + << otherAvgPhi / 1_degree + << " (was: " << prevOtherAvgPhi / 1_degree << ")"); try { - auto [newHlPhi, newAvgPhi] = detail::mergedPhiSector( + auto [newHlPhi, newAvgPhi, reversed] = detail::mergedPhiSector( hlPhi, avgPhi, otherHlPhi, otherAvgPhi, logger, tolerance); + Transform3 newTransform = *m_transform; + + if (externalRotation) { + ACTS_VERBOSE("Modifying transform for external rotation of " + << newAvgPhi / 1_degree); + newTransform = newTransform * AngleAxis3(newAvgPhi, Vector3::UnitZ()); + newAvgPhi = 0.; + } + auto newBounds = std::make_shared( r, bounds().get(CylinderBounds::eHalfLengthZ), newHlPhi, newAvgPhi); - return Surface::makeShared(transform(gctx), newBounds); + return {Surface::makeShared(newTransform, newBounds), + reversed}; } catch (const std::invalid_argument& e) { throw SurfaceMergingException(getSharedPtr(), other.getSharedPtr(), e.what()); diff --git a/Core/src/Surfaces/DiscSurface.cpp b/Core/src/Surfaces/DiscSurface.cpp index 9c6dd6f31b8..140047a5785 100644 --- a/Core/src/Surfaces/DiscSurface.cpp +++ b/Core/src/Surfaces/DiscSurface.cpp @@ -379,20 +379,29 @@ double Acts::DiscSurface::pathCorrection(const GeometryContext& gctx, return 1. / std::abs(normal(gctx).dot(direction)); } -std::shared_ptr Acts::DiscSurface::mergedWith( - const GeometryContext& gctx, const DiscSurface& other, - BinningValue direction, const Logger& logger) const { +std::pair, bool> +Acts::DiscSurface::mergedWith(const DiscSurface& other, BinningValue direction, + bool externalRotation, + const Logger& logger) const { using namespace Acts::UnitLiterals; - ACTS_DEBUG("Merging disc surfaces in " << binningValueName(direction) - << " direction"); + ACTS_DEBUG("Merging disc surfaces in " << direction << " direction"); - Transform3 otherLocal = transform(gctx).inverse() * other.transform(gctx); + if (m_associatedDetElement != nullptr || + other.m_associatedDetElement != nullptr) { + throw SurfaceMergingException(getSharedPtr(), other.getSharedPtr(), + "CylinderSurface::merge: surfaces are " + "associated with a detector element"); + } + assert(m_transform != nullptr && other.m_transform != nullptr); + + Transform3 otherLocal = m_transform->inverse() * *other.m_transform; constexpr auto tolerance = s_onSurfaceTolerance; // surface cannot have any relative rotation - if (!otherLocal.linear().isApprox(RotationMatrix3::Identity())) { + if (std::abs(otherLocal.linear().col(eX)[eZ]) >= tolerance || + std::abs(otherLocal.linear().col(eY)[eZ]) >= tolerance) { ACTS_ERROR("DiscSurface::merge: surfaces have relative rotation"); throw SurfaceMergingException( getSharedPtr(), other.getSharedPtr(), @@ -449,6 +458,13 @@ std::shared_ptr Acts::DiscSurface::mergedWith( << otherHlPhi / 1_degree); if (direction == Acts::BinningValue::binR) { + if (std::abs(otherLocal.linear().col(eY)[eX]) >= tolerance && + (!bounds->coversFullAzimuth() || !otherBounds->coversFullAzimuth())) { + throw SurfaceMergingException(getSharedPtr(), other.getSharedPtr(), + "DiscSurface::merge: surfaces have " + "relative rotation in z and phi sector"); + } + if (std::abs(minR - otherMaxR) > tolerance && std::abs(maxR - otherMinR) > tolerance) { ACTS_ERROR("DiscSurface::merge: surfaces are not touching r"); @@ -478,7 +494,8 @@ std::shared_ptr Acts::DiscSurface::mergedWith( auto newBounds = std::make_shared(newMinR, newMaxR, hlPhi, avgPhi); - return Surface::makeShared(transform(gctx), newBounds); + return {Surface::makeShared(*m_transform, newBounds), + minR > otherMinR}; } else if (direction == Acts::BinningValue::binPhi) { if (std::abs(maxR - otherMaxR) > tolerance || @@ -489,22 +506,49 @@ std::shared_ptr Acts::DiscSurface::mergedWith( "DiscSurface::merge: surfaces don't have same r bounds"); } + // Figure out signed relative rotation + Vector2 rotatedX = otherLocal.linear().col(eX).head<2>(); + ActsScalar zrotation = std::atan2(rotatedX[1], rotatedX[0]); + + ACTS_VERBOSE("this: [" << avgPhi / 1_degree << " +- " << hlPhi / 1_degree + << "]"); + ACTS_VERBOSE("other: [" << otherAvgPhi / 1_degree << " +- " + << otherHlPhi / 1_degree << "]"); + + ACTS_VERBOSE("Relative rotation around local z: " << zrotation / 1_degree); + + ActsScalar prevOtherAvgPhi = otherAvgPhi; + otherAvgPhi = detail::radian_sym(otherAvgPhi + zrotation); + ACTS_VERBOSE("~> local other average phi: " + << otherAvgPhi / 1_degree + << " (was: " << prevOtherAvgPhi / 1_degree << ")"); + try { - auto [newHlPhi, newAvgPhi] = detail::mergedPhiSector( + auto [newHlPhi, newAvgPhi, reversed] = detail::mergedPhiSector( hlPhi, avgPhi, otherHlPhi, otherAvgPhi, logger, tolerance); + Transform3 newTransform = *m_transform; + + if (externalRotation) { + ACTS_VERBOSE("Modifying transform for external rotation of " + << newAvgPhi / 1_degree); + newTransform = newTransform * AngleAxis3(newAvgPhi, Vector3::UnitZ()); + newAvgPhi = 0.; + } + auto newBounds = std::make_shared(minR, maxR, newHlPhi, newAvgPhi); - return Surface::makeShared(transform(gctx), newBounds); + return {Surface::makeShared(newTransform, newBounds), + reversed}; } catch (const std::invalid_argument& e) { throw SurfaceMergingException(getSharedPtr(), other.getSharedPtr(), e.what()); } } else { - ACTS_ERROR("DiscSurface::merge: invalid direction " - << binningValueName(direction)); + ACTS_ERROR("DiscSurface::merge: invalid direction " << direction); + throw SurfaceMergingException( getSharedPtr(), other.getSharedPtr(), "DiscSurface::merge: invalid direction " + binningValueName(direction)); diff --git a/Core/src/Surfaces/detail/MergeHelper.cpp b/Core/src/Surfaces/detail/MergeHelper.cpp index afb55c40570..7910381be0f 100644 --- a/Core/src/Surfaces/detail/MergeHelper.cpp +++ b/Core/src/Surfaces/detail/MergeHelper.cpp @@ -10,10 +10,36 @@ namespace Acts::detail { -std::pair mergedPhiSector( +std::tuple mergedPhiSector( ActsScalar hlPhi1, ActsScalar avgPhi1, ActsScalar hlPhi2, ActsScalar avgPhi2, const Logger& logger, ActsScalar tolerance) { using namespace Acts::UnitLiterals; + + if (std::abs(hlPhi1 - M_PI / 2.0) < tolerance && + std::abs(hlPhi2 - M_PI / 2.0) < tolerance) { + ACTS_VERBOSE("Both phi sectors cover a half circle"); + + ACTS_VERBOSE("-> distance between sectors: " + << detail::difference_periodic(avgPhi1, avgPhi2, 2 * M_PI) / + 1_degree); + + if (std::abs( + std::abs(detail::difference_periodic(avgPhi1, avgPhi2, 2 * M_PI)) - + M_PI) > tolerance) { + throw std::invalid_argument( + "Phi sectors cover half a circle but are not opposite"); + } + + ActsScalar newAvgPhi = detail::radian_sym(avgPhi1 + M_PI / 2.0); + ActsScalar newHlPhi = M_PI; + ACTS_VERBOSE("merged: [" + << detail::radian_sym(newAvgPhi - newHlPhi) / 1_degree << ", " + << detail::radian_sym(newAvgPhi + newHlPhi) / 1_degree + << "] ~> " << newAvgPhi / 1_degree << " +- " + << newHlPhi / 1_degree); + return {newHlPhi, newAvgPhi, false}; + } + ActsScalar minPhi1 = detail::radian_sym(-hlPhi1 + avgPhi1); ActsScalar maxPhi1 = detail::radian_sym(hlPhi1 + avgPhi1); @@ -36,17 +62,17 @@ std::pair mergedPhiSector( ActsScalar newMaxPhi{}, newMinPhi{}; ActsScalar newHlPhi = hlPhi1 + hlPhi2; + bool reversed = false; if (same(minPhi1, maxPhi2)) { - ACTS_VERBOSE("-> CCW ordering: one is 'left' of two"); + ACTS_VERBOSE("-> CCW ordering: one is 'right' of two"); newMinPhi = minPhi2; newMaxPhi = maxPhi1; - } else if (same(maxPhi1, minPhi2)) { - ACTS_VERBOSE("-> CW ordering: this is 'right' of other"); + ACTS_VERBOSE("-> CW ordering: one is 'left' of two"); newMinPhi = minPhi1; newMaxPhi = maxPhi2; - + reversed = true; } else { ACTS_ERROR("Phi ranges are incompatible"); throw std::invalid_argument("Phi ranges are incompatible"); @@ -59,7 +85,7 @@ std::pair mergedPhiSector( << newAvgPhi / 1_degree << " +- " << newHlPhi / 1_degree); - return {newHlPhi, newAvgPhi}; + return {newHlPhi, newAvgPhi, reversed}; } } // namespace Acts::detail diff --git a/Examples/Algorithms/Utilities/src/PrototracksToTracks.cpp b/Examples/Algorithms/Utilities/src/PrototracksToTracks.cpp index fe015fbc3f9..d3d0156ec51 100644 --- a/Examples/Algorithms/Utilities/src/PrototracksToTracks.cpp +++ b/Examples/Algorithms/Utilities/src/PrototracksToTracks.cpp @@ -63,7 +63,8 @@ ProcessCode PrototracksToTracks::execute(const AlgorithmContext& ctx) const { auto trackStateProxy = track.appendTrackState(Acts::TrackStatePropMask::None); trackStateProxy.typeFlags().set(Acts::TrackStateFlag::MeasurementFlag); - trackStateProxy.setUncalibratedSourceLink(slMap.at(idx)); + trackStateProxy.setUncalibratedSourceLink( + Acts::SourceLink{slMap.at(idx)}); } track.nMeasurements() = static_cast(protoTrack.size()); diff --git a/Examples/Framework/CMakeLists.txt b/Examples/Framework/CMakeLists.txt index 9ee5d487ddb..49fa92a53cb 100644 --- a/Examples/Framework/CMakeLists.txt +++ b/Examples/Framework/CMakeLists.txt @@ -31,9 +31,6 @@ target_link_libraries( ActsExamplesFramework PUBLIC ActsCore ActsFatras ActsPluginFpeMonitoring Boost::boost ROOT::Core ROOT::Hist PRIVATE std::filesystem) -acts_target_link_libraries_system( - ActsExamplesFramework - PRIVATE dfelibs) target_compile_definitions( ActsExamplesFramework PRIVATE BOOST_FILESYSTEM_NO_DEPRECATED) @@ -67,7 +64,7 @@ install( LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install( - DIRECTORY include/ActsExamples + DIRECTORY include/ActsExamples DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) add_subdirectory_if(ML ACTS_BUILD_PLUGIN_ONNX) diff --git a/Examples/Framework/ML/src/NeuralCalibrator.cpp b/Examples/Framework/ML/src/NeuralCalibrator.cpp index a5ee36db1df..29be5a07ad9 100644 --- a/Examples/Framework/ML/src/NeuralCalibrator.cpp +++ b/Examples/Framework/ML/src/NeuralCalibrator.cpp @@ -77,7 +77,7 @@ void ActsExamples::NeuralCalibrator::calibrate( const Acts::SourceLink& sourceLink, Acts::MultiTrajectory::TrackStateProxy& trackState) const { - trackState.setUncalibratedSourceLink(sourceLink); + trackState.setUncalibratedSourceLink(Acts::SourceLink{sourceLink}); const IndexSourceLink& idxSourceLink = sourceLink.get(); assert((idxSourceLink.index() < measurements.size()) and "Source link index is outside the container bounds"); diff --git a/Examples/Framework/src/EventData/MeasurementCalibration.cpp b/Examples/Framework/src/EventData/MeasurementCalibration.cpp index c76d7195033..dd0f45bee68 100644 --- a/Examples/Framework/src/EventData/MeasurementCalibration.cpp +++ b/Examples/Framework/src/EventData/MeasurementCalibration.cpp @@ -24,7 +24,7 @@ void ActsExamples::PassThroughCalibrator::calibrate( const Acts::CalibrationContext& /*cctx*/, const Acts::SourceLink& sourceLink, Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const { - trackState.setUncalibratedSourceLink(sourceLink); + trackState.setUncalibratedSourceLink(Acts::SourceLink{sourceLink}); const IndexSourceLink& idxSourceLink = sourceLink.get(); assert((idxSourceLink.index() < measurements.size()) && diff --git a/Examples/Framework/src/EventData/ScalingCalibrator.cpp b/Examples/Framework/src/EventData/ScalingCalibrator.cpp index 59a9bcef2dc..5172a9eda47 100644 --- a/Examples/Framework/src/EventData/ScalingCalibrator.cpp +++ b/Examples/Framework/src/EventData/ScalingCalibrator.cpp @@ -134,7 +134,7 @@ void ActsExamples::ScalingCalibrator::calibrate( const Acts::CalibrationContext& /*cctx*/, const Acts::SourceLink& sourceLink, Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const { - trackState.setUncalibratedSourceLink(sourceLink); + trackState.setUncalibratedSourceLink(Acts::SourceLink{sourceLink}); const IndexSourceLink& idxSourceLink = sourceLink.get(); assert((idxSourceLink.index() < measurements.size()) && diff --git a/Examples/Framework/src/Framework/Sequencer.cpp b/Examples/Framework/src/Framework/Sequencer.cpp index f1142e929ad..f1a3576e38e 100644 --- a/Examples/Framework/src/Framework/Sequencer.cpp +++ b/Examples/Framework/src/Framework/Sequencer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -50,8 +51,6 @@ #include #include #include -#include -#include namespace ActsExamples { @@ -390,27 +389,20 @@ inline std::string perEvent(D duration, std::size_t numEvents) { return asString(duration / numEvents) + "/event"; } -// Store timing data -struct TimingInfo { - std::string identifier; - double time_total_s = 0; - double time_perevent_s = 0; - - DFE_NAMEDTUPLE(TimingInfo, identifier, time_total_s, time_perevent_s); -}; - void storeTiming(const std::vector& identifiers, const std::vector& durations, std::size_t numEvents, const std::string& path) { - dfe::NamedTupleTsvWriter writer(path, 4); + std::ofstream file(path); + + file << "identifier,time_total_s,time_perevent_s\n"; + for (std::size_t i = 0; i < identifiers.size(); ++i) { - TimingInfo info; - info.identifier = identifiers[i]; - info.time_total_s = + const auto time_total_s = std::chrono::duration_cast(durations[i]).count(); - info.time_perevent_s = info.time_total_s / numEvents; - writer.append(info); + file << identifiers[i] << "," << time_total_s << "," + << time_total_s / numEvents; } + file << std::endl; } } // namespace diff --git a/Examples/Io/Csv/CMakeLists.txt b/Examples/Io/Csv/CMakeLists.txt index 7d367d68892..3cb9919f405 100644 --- a/Examples/Io/Csv/CMakeLists.txt +++ b/Examples/Io/Csv/CMakeLists.txt @@ -12,10 +12,10 @@ add_library( src/CsvTrackingGeometryWriter.cpp src/CsvTrackParameterReader.cpp src/CsvTrackParameterWriter.cpp - src/CsvSeedWriter.cpp - src/CsvTrackWriter.cpp - src/CsvDriftCircleReader.cpp - src/CsvMuonSimHitReader.cpp + src/CsvSeedWriter.cpp + src/CsvTrackWriter.cpp + src/CsvDriftCircleReader.cpp + src/CsvMuonSimHitReader.cpp src/CsvProtoTrackWriter.cpp src/CsvSpacePointWriter.cpp src/CsvExaTrkXGraphWriter.cpp @@ -30,9 +30,6 @@ target_link_libraries( ActsCore ActsExamplesFramework ActsExamplesDigitization Threads::Threads) -acts_target_link_libraries_system( - ActsExamplesIoCsv - PRIVATE dfelibs) install( TARGETS ActsExamplesIoCsv diff --git a/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvInputOutput.hpp b/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvInputOutput.hpp new file mode 100644 index 00000000000..a8cd535e926 --- /dev/null +++ b/Examples/Io/Csv/include/ActsExamples/Io/Csv/CsvInputOutput.hpp @@ -0,0 +1,648 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2024 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +// The contents of this file are originally sourced from +// https://github.com/acts-project/dfelibs/blob/master/dfe/dfe_io_dsv.hpp +// and +// https://github.com/acts-project/dfelibs/blob/master/dfe/dfe_namedtuple.hpp +// and were published with the following license statement: + +// SPDX-License-Identifier: MIT +// Copyright 2015,2018-2020 Moritz Kiehn +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/// Enable tuple-like access and conversion for selected class/struct members. +/// +/// This allows access to the selected members via `.get()` or `get(...)`, +/// conversion to equivalent `std::tuple<...>` via implicit conversion or +/// explicitly via `.tuple()`, and assignment from equivalent tuples. +/// The names can be accessed via `::names()`. +#define DFE_NAMEDTUPLE(name, ...) \ + using Tuple = decltype(::std::make_tuple(__VA_ARGS__)); \ + static ::std::array<::std::string, ::std::tuple_size::value> \ + names() { \ + return ::ActsExamples::detail_dfe::unstringify< \ + ::std::tuple_size::value>((#__VA_ARGS__)); \ + } \ + template \ + name& operator=(const ::std::tuple& other) { \ + ::std::tie(__VA_ARGS__) = other; \ + return *this; \ + } \ + template \ + name& operator=(::std::tuple&& other) { \ + ::std::tie(__VA_ARGS__) = ::std::forward>(other); \ + return *this; \ + } \ + operator Tuple() const { \ + return ::std::make_tuple(__VA_ARGS__); \ + } \ + Tuple tuple() const { \ + return ::std::make_tuple(__VA_ARGS__); \ + } \ + template \ + constexpr ::std::tuple_element_t& get() { \ + return ::std::get(std::tie(__VA_ARGS__)); \ + } \ + template <::std::size_t I> \ + constexpr const ::std::tuple_element_t& get() const { \ + return ::std::get(std::tie(__VA_ARGS__)); \ + } \ + template <::std::size_t I> \ + friend constexpr ::std::tuple_element_t& get(name& nt) { \ + return nt.template get(); \ + } \ + template <::std::size_t I> \ + friend constexpr const ::std::tuple_element_t& get( \ + const name& nt) { \ + return nt.template get(); \ + } \ + friend inline ::std::ostream& operator<<(::std::ostream& os, \ + const name& nt) { \ + return ::ActsExamples::detail_dfe::print_tuple( \ + os, nt.names(), nt.tuple(), \ + ::std::make_index_sequence<::std::tuple_size::value>{}); \ + } + +namespace ActsExamples { +// implementation helpers +namespace detail_dfe { + +// Reverse macro stringification. +// +// Splits a string of the form `a, b, c` into components a, b, and c. +template +constexpr std::array unstringify(const char* str) { + assert(str && "Input string must be non-null"); + + std::array out; + + for (std::size_t idx = 0; idx < N; ++idx) { + // skip leading whitespace + while ((*str != '\0') && (*str == ' ')) { + ++str; + } + // find the next separator or end-of-string + const char* sep = str; + while ((*sep != '\0') && (*sep != ',')) { + ++sep; + } + // store component w/o the separator + out[idx].assign(str, sep - str); + // we can quit as soon as we reached the end of the input + if (*sep == '\0') { + break; + } + // start search for next component after the separator + str = ++sep; + } + // TODO handle inconsistent number of entries? can it occur in expected use? + return out; +} + +// modified from http://stackoverflow.com/a/6245777 +template +inline std::ostream& print_tuple(std::ostream& os, const Names& n, + const Values& v, + std::index_sequence /*seq*/) { + // we want to execute some expression for every entry in the index pack. this + // requires a construction that can take a variable number of arguments into + // which we can unpack the indices. inside a function, constructing an + // array with an initializer list will do the job, i.e. we will effectively + // create the following statement + // + // int x[] = {...}; + // + // since we do not care about the actual values within the array, the + // initializer list is cast twice: once to the array type and then to void. + // this ignores the actual values and silences warnings about unused + // variables. to get the correct initializer list syntax, the array type + // must be typedef'd as a single type. what we get is + // + // using Vacuum = int[]; + // (void)Vacuum{...}; + // + // in order for this to work, the expression that we want to instantiate + // needs to evaluate to the element type of the array (here: `int`). this can + // be done with the comma operator (yep, `,` is a weird but helpful operator) + // for arbitrary expressions. `(, )` executes both expressions + // but evaluates only to the return value of the second expression. thus, + // `(, 0)` executes `` but always evaluates to an integer of value + // zero. if uses the index pack variable `I` in the following setup + // + // (void)Vacuum{(, 0)...}; + // + // it is instantiatied for each element within the pack (with appropriate , + // placements). thus, effectively looping over every entry in the pack and + // calling for each (here: printing to os); + using std::get; + using Vacuum = int[]; + (void)Vacuum{ + (os << ((0 < I) ? " " : "") << get(n) << "=" << get(v), 0)...}; + return os; +} + +/// Write arbitrary data as delimiter-separated values into a text file. +template +class DsvWriter { + public: + DsvWriter() = delete; + DsvWriter(const DsvWriter&) = delete; + DsvWriter(DsvWriter&&) = default; + ~DsvWriter() = default; + DsvWriter& operator=(const DsvWriter&) = delete; + DsvWriter& operator=(DsvWriter&&) = default; + + /// Create a file at the given path. Overwrites existing data. + /// + /// \param columns Column names, fixes the number of columns for the file + /// \param path Path to the output file + /// \param precision Output floating point precision + DsvWriter(const std::vector& columns, const std::string& path, + int precision = std::numeric_limits::max_digits10); + + /// Append arguments as a new row to the file. + /// + /// Each argument corresponds to one column. The writer ensures that the + /// number of columns written match the number of columns that were specified + /// during construction. + /// + /// \note `std::vector` arguments are automatically unpacked and each entry + /// is written as a separate column. + template + void append(Arg0&& arg0, Args&&... args); + + private: + std::ofstream m_file; + std::size_t m_num_columns; + + // enable_if to prevent this overload to be used for std::vector as well + template + static std::enable_if_t>::value || + std::is_convertible::value, + unsigned> + write(T&& x, std::ostream& os); + template + static unsigned write(const std::vector& xs, std::ostream& os); +}; + +/// Read arbitrary data as delimiter-separated values from a text file. +template +class DsvReader { + public: + DsvReader() = delete; + DsvReader(const DsvReader&) = delete; + DsvReader(DsvReader&&) = default; + ~DsvReader() = default; + DsvReader& operator=(const DsvReader&) = delete; + DsvReader& operator=(DsvReader&&) = default; + + /// Open a file at the given path. + /// + /// \param path Path to the input file + DsvReader(const std::string& path); + + /// Read the next line from the file. + /// + /// \returns true if the line was successfully read + /// \returns false if no more lines are available + bool read(std::vector& columns); + + /// Return the number of lines read so far. + std::size_t num_lines() const { return m_num_lines; } + + private: + std::ifstream m_file; + std::string m_line; + std::size_t m_num_lines = 0; +}; + +/// Write records as delimiter-separated values into a text file. +template +class NamedTupleDsvWriter { + public: + NamedTupleDsvWriter() = delete; + NamedTupleDsvWriter(const NamedTupleDsvWriter&) = delete; + NamedTupleDsvWriter(NamedTupleDsvWriter&&) = default; + ~NamedTupleDsvWriter() = default; + NamedTupleDsvWriter& operator=(const NamedTupleDsvWriter&) = delete; + NamedTupleDsvWriter& operator=(NamedTupleDsvWriter&&) = default; + + /// Create a file at the given path. Overwrites existing data. + /// + /// \param path Path to the output file + /// \param precision Output floating point precision + NamedTupleDsvWriter(const std::string& path, + int precision = std::numeric_limits::max_digits10) + : m_writer(colum_names(), path, precision) {} + + /// Append a record to the file. + void append(const NamedTuple& record) { + append_impl(record, + std::make_index_sequence< + std::tuple_size::value>{}); + } + + private: + DsvWriter m_writer; + + static std::vector colum_names() { + const auto& from_record = NamedTuple::names(); + return {from_record.begin(), from_record.end()}; + } + template + void append_impl(const NamedTuple& values, + std::index_sequence /*seq*/) { + using std::get; + m_writer.append(get(values)...); + } +}; + +// string conversion helper functions + +template +static void parse(const std::string& str, T& value) { + // TODO use somtehing w/ lower overhead then stringstream e.g. std::from_chars + std::istringstream is(str); + is >> value; +} + +/// Read records as delimiter-separated values from a text file. +/// +/// The reader is strict about its input format to avoid ambiguities. If +/// header verification is disabled, the first line will be skipped and each +/// line must contain exactly as many columns as there are tuple members in +/// exactly the same order. If header verification is enabled, the first line +/// is interpreted as the header. Names in the header must match exactly to +/// the tuple members but can be in arbitrary order. The file can contain +/// extra columns that are not tuple members. Each following row must have +/// exactly the same number of columns as the header. +template +class NamedTupleDsvReader { + public: + NamedTupleDsvReader() = delete; + NamedTupleDsvReader(const NamedTupleDsvReader&) = delete; + NamedTupleDsvReader(NamedTupleDsvReader&&) = default; + ~NamedTupleDsvReader() = default; + NamedTupleDsvReader& operator=(const NamedTupleDsvReader&) = delete; + NamedTupleDsvReader& operator=(NamedTupleDsvReader&&) = default; + + /// Open a file at the given path. + /// + /// \param path Path to the input file + /// \param optional_columns Record columns that can be missing in the file + /// \param verify_header true to check header column names, false to skip + /// + /// The set of optional columns must match names in the record. When allowing + /// optional columns, header verification must be set to true. + NamedTupleDsvReader(const std::string& path, + const std::vector& optional_columns = {}, + bool verify_header = true); + + /// Read the next record from the file. + /// + /// Extra columns in the file will be ignored. Elements of the record that + /// correspond to missing, optional columns will not be set and retain + /// their value. + /// + /// \returns true if a record was successfully read + /// \returns false if no more records are available + bool read(NamedTuple& record); + + /// Read the next record and any extra columns from the file. + /// + /// \returns true if a record was successfully read + /// \returns false if no more records are available + template + bool read(NamedTuple& record, std::vector& extra); + + /// Return the number of additional columns that are not part of the tuple. + std::size_t num_extra_columns() const { return m_extra_columns.size(); } + /// Return the number of records read so far. + std::size_t num_records() const { return m_reader.num_lines() - 1u; } + + private: + // the equivalent std::tuple-like type + using Tuple = typename NamedTuple::Tuple; + + DsvReader m_reader; + std::vector m_columns; + // #columns is fixed to a reasonable value after reading the header + std::size_t m_num_columns = SIZE_MAX; + // map tuple index to column index in the file, SIZE_MAX for missing elements + std::array::value> m_tuple_column_map; + // column indices that do not map to a tuple items + std::vector m_extra_columns; + + void use_default_columns(); + void parse_header(const std::vector& optional_columns); + template + void parse_record(NamedTuple& record, + std::index_sequence /*seq*/) const { + // see namedtuple_impl::print_tuple for explanation + // allow different column ordering on file and optional columns + using Vacuum = int[]; + (void)Vacuum{(parse_element(record), 0)...}; + } + template + void parse_element(NamedTuple& record) const { + using std::get; + if (m_tuple_column_map[I] != SIZE_MAX) { + parse(m_columns[m_tuple_column_map[I]], get(record)); + } + } +}; + +// implementation writer + +template +inline DsvWriter::DsvWriter(const std::vector& columns, + const std::string& path, int precision) + : m_file(path, + std::ios_base::binary | std::ios_base::out | std::ios_base::trunc), + m_num_columns(columns.size()) { + if (!m_file.is_open() || m_file.fail()) { + throw std::runtime_error("Could not open file '" + path + "'"); + } + m_file.precision(precision); + if (m_num_columns == 0) { + throw std::invalid_argument("No columns were specified"); + } + // write column names as header row + append(columns); +} + +template +template +inline void DsvWriter::append(Arg0&& arg0, Args&&... args) { + // we can only check how many columns were written after they have been + // written. write to temporary first to prevent bad data on file. + std::stringstream line; + // ensure consistent formatting + line.precision(m_file.precision()); + unsigned written_columns[] = { + // write the first item without a delimiter and store columns written + write(std::forward(arg0), line), + // for all other items, write the delimiter followed by the item itself + // (, ) use the comma operator (yep, ',' in c++ is a weird + // but helpful operator) to execute both expression and return the return + // value of the last one, i.e. here that's the number of columns written. + // the ... pack expansion creates this expression for all arguments + (line << Delimiter, write(std::forward(args), line))..., + }; + line << '\n'; + // validate that the total number of written columns matches the specs. + unsigned total_columns = 0; + for (auto nc : written_columns) { + total_columns += nc; + } + if (total_columns < m_num_columns) { + throw std::invalid_argument("Not enough columns"); + } + if (m_num_columns < total_columns) { + throw std::invalid_argument("Too many columns"); + } + // write the line to disk and check that it actually happened + m_file << line.rdbuf(); + if (!m_file.good()) { + throw std::runtime_error("Could not write data to file"); + } +} + +template +template +inline std::enable_if_t>::value || + std::is_convertible::value, + unsigned> +DsvWriter::write(T&& x, std::ostream& os) { + os << x; + return 1u; +} + +template +template +inline unsigned DsvWriter::write(const std::vector& xs, + std::ostream& os) { + unsigned n = 0; + for (const auto& x : xs) { + if (0 < n) { + os << Delimiter; + } + os << x; + n += 1; + } + return n; +} + +// implementation reader + +template +inline DsvReader::DsvReader(const std::string& path) + : m_file(path, std::ios_base::binary | std::ios_base::in) { + if (!m_file.is_open() || m_file.fail()) { + throw std::runtime_error("Could not open file '" + path + "'"); + } +} + +template +inline bool DsvReader::read(std::vector& columns) { + // read the next line and check for both end-of-file and errors + std::getline(m_file, m_line); + if (m_file.eof()) { + return false; + } + if (m_file.fail()) { + throw std::runtime_error(std::string("Could not read line ") + + std::to_string(m_num_lines)); + } + m_num_lines += 1; + + // split the line into columns + columns.clear(); + for (std::string::size_type pos = 0; pos < m_line.size();) { + auto del = m_line.find_first_of(Delimiter, pos); + if (del == std::string::npos) { + // reached the end of the line; also determines the last column + columns.emplace_back(m_line, pos); + break; + } else { + columns.emplace_back(m_line, pos, del - pos); + // start next column search after the delimiter + pos = del + 1; + } + } + return true; +} + +// implementation named tuple reader + +template +inline NamedTupleDsvReader::NamedTupleDsvReader( + const std::string& path, const std::vector& optional_columns, + bool verify_header) + : m_reader(path) { + // optional columns only work if we verify the header + if ((!optional_columns.empty()) && (!verify_header)) { + throw std::runtime_error( + "Optional columns can not be used without header verification"); + } + // first line is always the header + if (!m_reader.read(m_columns)) { + throw std::runtime_error("Could not read header from '" + path + "'"); + } + if (verify_header) { + parse_header(optional_columns); + } else { + use_default_columns(); + } +} + +template +inline bool NamedTupleDsvReader::read( + NamedTuple& record) { + if (!m_reader.read(m_columns)) { + return false; + } + // check for consistent entries per-line + if (m_columns.size() < m_num_columns) { + throw std::runtime_error("Too few columns in line " + + std::to_string(m_reader.num_lines())); + } + if (m_num_columns < m_columns.size()) { + throw std::runtime_error("Too many columns in line " + + std::to_string(m_reader.num_lines())); + } + // convert to tuple + parse_record(record, + std::make_index_sequence::value>{}); + return true; +} + +template +template +inline bool NamedTupleDsvReader::read( + NamedTuple& record, std::vector& extra) { + // parse columns belonging to the regular record + if (!read(record)) { + return false; + } + // parse extra columns + extra.resize(m_extra_columns.size()); + for (std::size_t i = 0; i < m_extra_columns.size(); ++i) { + parse(m_columns[m_extra_columns[i]], extra[i]); + } + return true; +} + +template +inline void NamedTupleDsvReader::use_default_columns() { + // assume row content is identical in content and order to the tuple + m_num_columns = std::tuple_size::value; + for (std::size_t i = 0; i < m_tuple_column_map.size(); ++i) { + m_tuple_column_map[i] = i; + } + // no extra columns by construction + m_extra_columns.clear(); +} + +template +inline void NamedTupleDsvReader::parse_header( + const std::vector& optional_columns) { + const auto& names = NamedTuple::names(); + + // the number of header columns fixes the expected number of data columns + m_num_columns = m_columns.size(); + + // check that all non-optional columns are available + for (const auto& name : names) { + // no need to for availability if the column is optional + auto o = std::find(optional_columns.begin(), optional_columns.end(), name); + if (o != optional_columns.end()) { + continue; + } + // missing, non-optional column mean we can not continue + auto c = std::find(m_columns.begin(), m_columns.end(), name); + if (c == m_columns.end()) { + throw std::runtime_error("Missing header column '" + name + "'"); + } + } + + // ensure missing columns are correctly marked as such + m_tuple_column_map.fill(SIZE_MAX); + + // determine column-tuple mapping and extra column indices + m_extra_columns.clear(); + for (std::size_t i = 0; i < m_columns.size(); ++i) { + // find the position of the column in the tuple. + auto it = std::find(names.begin(), names.end(), m_columns[i]); + if (it != names.end()) { + // establish mapping between column and tuple item position + m_tuple_column_map[std::distance(names.begin(), it)] = i; + } else { + // record non-tuple columns + m_extra_columns.push_back(i); + } + } +} + +#undef _UNUSED + +} // namespace detail_dfe + +/// Write arbitrary data as comma-separated values into as text file. +using CsvWriter = detail_dfe::DsvWriter<','>; + +/// Write arbitrary data as tab-separated values into as text file. +using TsvWriter = detail_dfe::DsvWriter<'\t'>; + +/// Write tuple-like records as comma-separated values into a text file. +template +using NamedTupleCsvWriter = detail_dfe::NamedTupleDsvWriter<',', T>; + +/// Read tuple-like records from a comma-separated file. +template +using NamedTupleCsvReader = detail_dfe::NamedTupleDsvReader<',', T>; + +/// Write tuple-like records as tab-separated values into a text file. +template +using NamedTupleTsvWriter = detail_dfe::NamedTupleDsvWriter<'\t', T>; + +/// Read tuple-like records from a tab-separated file. +template +using NamedTupleTsvReader = detail_dfe::NamedTupleDsvReader<'\t', T>; + +} // namespace ActsExamples diff --git a/Examples/Io/Csv/src/CsvBFieldWriter.cpp b/Examples/Io/Csv/src/CsvBFieldWriter.cpp index eca5f14ec61..05e2c8ca93f 100644 --- a/Examples/Io/Csv/src/CsvBFieldWriter.cpp +++ b/Examples/Io/Csv/src/CsvBFieldWriter.cpp @@ -15,14 +15,13 @@ #include "Acts/Utilities/Logger.hpp" #include "Acts/Utilities/Result.hpp" #include "Acts/Utilities/VectorHelpers.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include #include #include #include -#include - namespace ActsExamples { template void CsvBFieldWriter::run(const Config& config, @@ -49,7 +48,7 @@ void CsvBFieldWriter::run(const Config& config, // Initialize a CSV writer to the specified filename using the specified // column names. - dfe::io_dsv_impl::DsvWriter<','> writer(fields, config.fileName); + CsvWriter writer(fields, config.fileName); // We proceed by finding the number of bins, as well as the minimum and // maximum coordinates. This process depends quite heavily on the structure diff --git a/Examples/Io/Csv/src/CsvDriftCircleReader.cpp b/Examples/Io/Csv/src/CsvDriftCircleReader.cpp index 1a9eed4caa2..9fdb0d86083 100644 --- a/Examples/Io/Csv/src/CsvDriftCircleReader.cpp +++ b/Examples/Io/Csv/src/CsvDriftCircleReader.cpp @@ -12,6 +12,7 @@ #include "Acts/Geometry/GeometryIdentifier.hpp" #include "ActsExamples/EventData/DriftCircle.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include "ActsFatras/EventData/Barcode.hpp" #include "ActsFatras/EventData/Hit.hpp" @@ -19,8 +20,6 @@ #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvDriftCircleReader::CsvDriftCircleReader( @@ -56,7 +55,7 @@ ActsExamples::ProcessCode ActsExamples::CsvDriftCircleReader::read( auto path = perEventFilepath(m_cfg.inputDir, m_cfg.inputStem + ".csv", ctx.eventNumber); - dfe::NamedTupleCsvReader reader(path); + ActsExamples::NamedTupleCsvReader reader(path); DriftCircleContainer DriftCircles; MuonDriftCircleData data; diff --git a/Examples/Io/Csv/src/CsvExaTrkXGraphReader.cpp b/Examples/Io/Csv/src/CsvExaTrkXGraphReader.cpp index 81eaad7eb51..9caf1df4142 100644 --- a/Examples/Io/Csv/src/CsvExaTrkXGraphReader.cpp +++ b/Examples/Io/Csv/src/CsvExaTrkXGraphReader.cpp @@ -13,6 +13,7 @@ #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include "ActsFatras/EventData/Barcode.hpp" #include "ActsFatras/EventData/Particle.hpp" @@ -24,8 +25,6 @@ #include #include -#include - #include "CsvOutputData.hpp" namespace ActsExamples { @@ -54,7 +53,7 @@ ProcessCode CsvExaTrkXGraphReader::read(const AlgorithmContext& ctx) { auto path = perEventFilepath(m_cfg.inputDir, m_cfg.inputStem + ".csv", ctx.eventNumber); // vt and m are an optional columns - dfe::NamedTupleCsvReader reader(path, {"vt", "m"}); + ActsExamples::NamedTupleCsvReader reader(path, {"vt", "m"}); GraphData data; Graph g; diff --git a/Examples/Io/Csv/src/CsvExaTrkXGraphWriter.cpp b/Examples/Io/Csv/src/CsvExaTrkXGraphWriter.cpp index 49c394b7ed2..664ed1f5fb5 100644 --- a/Examples/Io/Csv/src/CsvExaTrkXGraphWriter.cpp +++ b/Examples/Io/Csv/src/CsvExaTrkXGraphWriter.cpp @@ -12,15 +12,13 @@ #include "Acts/Definitions/Common.hpp" #include "Acts/Definitions/Units.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include "ActsFatras/EventData/Barcode.hpp" #include #include -#include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvExaTrkXGraphWriter::CsvExaTrkXGraphWriter( @@ -42,7 +40,7 @@ ActsExamples::ProcessCode ActsExamples::CsvExaTrkXGraphWriter::writeT( std::string path = perEventFilepath( m_cfg.outputDir, m_cfg.outputStem + ".csv", ctx.eventNumber); - dfe::NamedTupleCsvWriter writer(path); + ActsExamples::NamedTupleCsvWriter writer(path); const auto nEdges = graph.edges.size() / 2; for (auto i = 0ul; i < nEdges; ++i) { diff --git a/Examples/Io/Csv/src/CsvMeasurementReader.cpp b/Examples/Io/Csv/src/CsvMeasurementReader.cpp index 3b9cc2bb438..e1c31d52b63 100644 --- a/Examples/Io/Csv/src/CsvMeasurementReader.cpp +++ b/Examples/Io/Csv/src/CsvMeasurementReader.cpp @@ -18,6 +18,7 @@ #include "ActsExamples/EventData/IndexSourceLink.hpp" #include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include @@ -29,8 +30,6 @@ #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvMeasurementReader::CsvMeasurementReader( @@ -108,7 +107,7 @@ inline std::vector readEverything( const std::string& inputDir, const std::string& filename, const std::vector& optionalColumns, std::size_t event) { std::string path = ActsExamples::perEventFilepath(inputDir, filename, event); - dfe::NamedTupleCsvReader reader(path, optionalColumns); + ActsExamples::NamedTupleCsvReader reader(path, optionalColumns); std::vector everything; Data one; diff --git a/Examples/Io/Csv/src/CsvMeasurementWriter.cpp b/Examples/Io/Csv/src/CsvMeasurementWriter.cpp index 723ea7635a5..a5003650124 100644 --- a/Examples/Io/Csv/src/CsvMeasurementWriter.cpp +++ b/Examples/Io/Csv/src/CsvMeasurementWriter.cpp @@ -15,6 +15,7 @@ #include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/IndexSourceLink.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include "ActsExamples/Utilities/Range.hpp" #include "ActsFatras/Digitization/Channelizer.hpp" @@ -26,8 +27,6 @@ #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvMeasurementWriter::CsvMeasurementWriter( @@ -64,22 +63,24 @@ ActsExamples::ProcessCode ActsExamples::CsvMeasurementWriter::writeT( std::string pathMeasurementSimHitMap = perEventFilepath( m_cfg.outputDir, "measurement-simhit-map.csv", ctx.eventNumber); - dfe::NamedTupleCsvWriter writerMeasurements( + ActsExamples::NamedTupleCsvWriter writerMeasurements( pathMeasurements, m_cfg.outputPrecision); - std::optional> writerCells{std::nullopt}; + std::optional> writerCells{ + std::nullopt}; if (!m_cfg.inputClusters.empty()) { ACTS_VERBOSE( "Set up writing of clusters from collection: " << m_cfg.inputClusters); clusters = m_inputClusters(ctx); std::string pathCells = perEventFilepath(m_cfg.outputDir, "cells.csv", ctx.eventNumber); - writerCells = - dfe::NamedTupleCsvWriter{pathCells, m_cfg.outputPrecision}; + writerCells = ActsExamples::NamedTupleCsvWriter{ + pathCells, m_cfg.outputPrecision}; } - dfe::NamedTupleCsvWriter writerMeasurementSimHitMap( - pathMeasurementSimHitMap, m_cfg.outputPrecision); + ActsExamples::NamedTupleCsvWriter + writerMeasurementSimHitMap(pathMeasurementSimHitMap, + m_cfg.outputPrecision); MeasurementData meas; CellData cell; diff --git a/Examples/Io/Csv/src/CsvMuonSimHitReader.cpp b/Examples/Io/Csv/src/CsvMuonSimHitReader.cpp index fbc6f4e1592..d6d166eee7d 100644 --- a/Examples/Io/Csv/src/CsvMuonSimHitReader.cpp +++ b/Examples/Io/Csv/src/CsvMuonSimHitReader.cpp @@ -12,6 +12,7 @@ #include "Acts/Geometry/GeometryIdentifier.hpp" #include "ActsExamples/EventData/MuonSimHit.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include "ActsFatras/EventData/Barcode.hpp" #include "ActsFatras/EventData/Hit.hpp" @@ -19,8 +20,6 @@ #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvMuonSimHitReader::CsvMuonSimHitReader( @@ -56,7 +55,7 @@ ActsExamples::ProcessCode ActsExamples::CsvMuonSimHitReader::read( auto path = perEventFilepath(m_cfg.inputDir, m_cfg.inputStem + ".csv", ctx.eventNumber); - dfe::NamedTupleCsvReader reader(path); + ActsExamples::NamedTupleCsvReader reader(path); MuonSimHitData data; diff --git a/Examples/Io/Csv/src/CsvOutputData.hpp b/Examples/Io/Csv/src/CsvOutputData.hpp index 5cff2f69fa1..af977ecbc5f 100644 --- a/Examples/Io/Csv/src/CsvOutputData.hpp +++ b/Examples/Io/Csv/src/CsvOutputData.hpp @@ -12,8 +12,6 @@ #include -#include - namespace ActsExamples { struct ParticleData { diff --git a/Examples/Io/Csv/src/CsvParticleReader.cpp b/Examples/Io/Csv/src/CsvParticleReader.cpp index 563fcb519cd..fa8a17f0f13 100644 --- a/Examples/Io/Csv/src/CsvParticleReader.cpp +++ b/Examples/Io/Csv/src/CsvParticleReader.cpp @@ -13,6 +13,7 @@ #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/EventData/SimParticle.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include "ActsFatras/EventData/Barcode.hpp" #include "ActsFatras/EventData/Particle.hpp" @@ -23,8 +24,6 @@ #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvParticleReader::CsvParticleReader( @@ -60,7 +59,7 @@ ActsExamples::ProcessCode ActsExamples::CsvParticleReader::read( auto path = perEventFilepath(m_cfg.inputDir, m_cfg.inputStem + ".csv", ctx.eventNumber); // vt and m are an optional columns - dfe::NamedTupleCsvReader reader(path, {"vt", "m"}); + ActsExamples::NamedTupleCsvReader reader(path, {"vt", "m"}); ParticleData data; while (reader.read(data)) { diff --git a/Examples/Io/Csv/src/CsvParticleWriter.cpp b/Examples/Io/Csv/src/CsvParticleWriter.cpp index 779ead1a2a8..db2d38d6af9 100644 --- a/Examples/Io/Csv/src/CsvParticleWriter.cpp +++ b/Examples/Io/Csv/src/CsvParticleWriter.cpp @@ -9,6 +9,7 @@ #include "ActsExamples/Io/Csv/CsvParticleWriter.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include "ActsFatras/EventData/Barcode.hpp" #include "ActsFatras/EventData/Particle.hpp" @@ -17,8 +18,6 @@ #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvParticleWriter::CsvParticleWriter( @@ -36,8 +35,8 @@ ActsExamples::ProcessCode ActsExamples::CsvParticleWriter::writeT( const SimParticleContainer& particles) { auto pathParticles = perEventFilepath( m_cfg.outputDir, m_cfg.outputStem + ".csv", ctx.eventNumber); - dfe::NamedTupleCsvWriter writer(pathParticles, - m_cfg.outputPrecision); + ActsExamples::NamedTupleCsvWriter writer(pathParticles, + m_cfg.outputPrecision); ParticleData data; for (const auto& particle : particles) { diff --git a/Examples/Io/Csv/src/CsvProtoTrackWriter.cpp b/Examples/Io/Csv/src/CsvProtoTrackWriter.cpp index 0f7b1b0adfd..1b6c3d4ae37 100644 --- a/Examples/Io/Csv/src/CsvProtoTrackWriter.cpp +++ b/Examples/Io/Csv/src/CsvProtoTrackWriter.cpp @@ -14,6 +14,7 @@ #include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/SimSpacePoint.hpp" #include "ActsExamples/Framework/WhiteBoard.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/EventDataTransforms.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include "ActsExamples/Utilities/Range.hpp" @@ -22,8 +23,6 @@ #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvProtoTrackWriter::CsvProtoTrackWriter( @@ -49,7 +48,8 @@ ActsExamples::ProcessCode ActsExamples::CsvProtoTrackWriter::writeT( std::string path = perEventFilepath(m_cfg.outputDir, "prototracks.csv", ctx.eventNumber); - dfe::NamedTupleCsvWriter writer(path, m_cfg.outputPrecision); + ActsExamples::NamedTupleCsvWriter writer( + path, m_cfg.outputPrecision); for (auto trackId = 0ul; trackId < tracks.size(); ++trackId) { for (Index measurmentId : tracks[trackId]) { diff --git a/Examples/Io/Csv/src/CsvSimHitReader.cpp b/Examples/Io/Csv/src/CsvSimHitReader.cpp index a339938753c..5e9d6180389 100644 --- a/Examples/Io/Csv/src/CsvSimHitReader.cpp +++ b/Examples/Io/Csv/src/CsvSimHitReader.cpp @@ -12,6 +12,7 @@ #include "Acts/Geometry/GeometryIdentifier.hpp" #include "ActsExamples/EventData/SimHit.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include "ActsFatras/EventData/Barcode.hpp" #include "ActsFatras/EventData/Hit.hpp" @@ -19,8 +20,6 @@ #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvSimHitReader::CsvSimHitReader( @@ -55,7 +54,7 @@ ActsExamples::ProcessCode ActsExamples::CsvSimHitReader::read( auto path = perEventFilepath(m_cfg.inputDir, m_cfg.inputStem + ".csv", ctx.eventNumber); - dfe::NamedTupleCsvReader reader(path); + ActsExamples::NamedTupleCsvReader reader(path); SimHitContainer::sequence_type unordered; SimHitData data; diff --git a/Examples/Io/Csv/src/CsvSimHitWriter.cpp b/Examples/Io/Csv/src/CsvSimHitWriter.cpp index f70265a6365..96b628afb33 100644 --- a/Examples/Io/Csv/src/CsvSimHitWriter.cpp +++ b/Examples/Io/Csv/src/CsvSimHitWriter.cpp @@ -14,6 +14,7 @@ #include "Acts/Geometry/GeometryIdentifier.hpp" #include "ActsExamples/EventData/SimHit.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include "ActsFatras/EventData/Barcode.hpp" #include "ActsFatras/EventData/Hit.hpp" @@ -21,8 +22,6 @@ #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvSimHitWriter::CsvSimHitWriter( @@ -41,8 +40,8 @@ ActsExamples::ProcessCode ActsExamples::CsvSimHitWriter::writeT( std::string pathSimHit = perEventFilepath( m_cfg.outputDir, m_cfg.outputStem + ".csv", ctx.eventNumber); - dfe::NamedTupleCsvWriter writerSimHit(pathSimHit, - m_cfg.outputPrecision); + ActsExamples::NamedTupleCsvWriter writerSimHit( + pathSimHit, m_cfg.outputPrecision); // CsvOutputData struct SimHitData simhit; diff --git a/Examples/Io/Csv/src/CsvSpacePointReader.cpp b/Examples/Io/Csv/src/CsvSpacePointReader.cpp index 6509c24a79e..2db167975f9 100644 --- a/Examples/Io/Csv/src/CsvSpacePointReader.cpp +++ b/Examples/Io/Csv/src/CsvSpacePointReader.cpp @@ -12,6 +12,7 @@ #include "Acts/EventData/SourceLink.hpp" #include "ActsExamples/EventData/SimSpacePoint.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include @@ -21,7 +22,6 @@ #include #include -#include #include "CsvOutputData.hpp" @@ -61,7 +61,7 @@ ActsExamples::ProcessCode ActsExamples::CsvSpacePointReader::read( const auto& path = perEventFilepath(m_cfg.inputDir, filename + ".csv", ctx.eventNumber); - dfe::NamedTupleCsvReader reader(path); + ActsExamples::NamedTupleCsvReader reader(path); SpacePointData data; while (reader.read(data)) { diff --git a/Examples/Io/Csv/src/CsvSpacePointWriter.cpp b/Examples/Io/Csv/src/CsvSpacePointWriter.cpp index 4c27fbc0704..6fecad15461 100644 --- a/Examples/Io/Csv/src/CsvSpacePointWriter.cpp +++ b/Examples/Io/Csv/src/CsvSpacePointWriter.cpp @@ -16,13 +16,12 @@ #include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Framework/ProcessCode.hpp" #include "ActsExamples/Framework/WriterT.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvSpacepointWriter::CsvSpacepointWriter( @@ -44,8 +43,8 @@ ActsExamples::ProcessCode ActsExamples::CsvSpacepointWriter::writeT( std::string pathSP = perEventFilepath(m_cfg.outputDir, "spacepoint.csv", ctx.eventNumber); - dfe::NamedTupleCsvWriter writerSP(pathSP, - m_cfg.outputPrecision); + ActsExamples::NamedTupleCsvWriter writerSP( + pathSP, m_cfg.outputPrecision); SpacepointData spData{}; for (const auto& sp : spacepoints) { diff --git a/Examples/Io/Csv/src/CsvTrackParameterReader.cpp b/Examples/Io/Csv/src/CsvTrackParameterReader.cpp index 46a7ad93055..3e9c4ebb3a6 100644 --- a/Examples/Io/Csv/src/CsvTrackParameterReader.cpp +++ b/Examples/Io/Csv/src/CsvTrackParameterReader.cpp @@ -14,14 +14,13 @@ #include "Acts/Surfaces/Surface.hpp" #include "ActsExamples/EventData/Track.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvTrackParameterReader::CsvTrackParameterReader( @@ -60,7 +59,7 @@ ActsExamples::ProcessCode ActsExamples::CsvTrackParameterReader::read( auto path = perEventFilepath(m_cfg.inputDir, m_cfg.inputStem + ".csv", ctx.eventNumber); - dfe::NamedTupleCsvReader reader(path); + ActsExamples::NamedTupleCsvReader reader(path); TrackParameterData d{}; while (reader.read(d)) { diff --git a/Examples/Io/Csv/src/CsvTrackParameterWriter.cpp b/Examples/Io/Csv/src/CsvTrackParameterWriter.cpp index af8d72983f6..6251f983b4b 100644 --- a/Examples/Io/Csv/src/CsvTrackParameterWriter.cpp +++ b/Examples/Io/Csv/src/CsvTrackParameterWriter.cpp @@ -12,13 +12,12 @@ #include "Acts/EventData/GenericBoundTrackParameters.hpp" #include "ActsExamples/EventData/Trajectories.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include #include -#include - #include "CsvOutputData.hpp" ActsExamples::CsvTrackParameterWriter::CsvTrackParameterWriter( @@ -68,8 +67,8 @@ ActsExamples::ProcessCode ActsExamples::CsvTrackParameterWriter::write( std::string path = perEventFilepath(m_cfg.outputDir, m_cfg.outputStem, ctx.eventNumber); - dfe::NamedTupleCsvWriter writer(path, - m_cfg.outputPrecision); + ActsExamples::NamedTupleCsvWriter writer( + path, m_cfg.outputPrecision); TrackParameterData data{}; for (const auto& tp : inputTrackParameters) { diff --git a/Examples/Io/Csv/src/CsvTrackingGeometryWriter.cpp b/Examples/Io/Csv/src/CsvTrackingGeometryWriter.cpp index 67b31f32289..0d98c8d0f54 100644 --- a/Examples/Io/Csv/src/CsvTrackingGeometryWriter.cpp +++ b/Examples/Io/Csv/src/CsvTrackingGeometryWriter.cpp @@ -25,6 +25,7 @@ #include "Acts/Utilities/IAxis.hpp" #include "Acts/Utilities/Logger.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" +#include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" #include @@ -33,8 +34,6 @@ #include #include -#include - #include "CsvOutputData.hpp" using namespace ActsExamples; @@ -60,9 +59,9 @@ std::string CsvTrackingGeometryWriter::name() const { namespace { -using SurfaceWriter = dfe::NamedTupleCsvWriter; -using SurfaceGridWriter = dfe::NamedTupleCsvWriter; -using LayerVolumeWriter = dfe::NamedTupleCsvWriter; +using SurfaceWriter = ActsExamples::NamedTupleCsvWriter; +using SurfaceGridWriter = ActsExamples::NamedTupleCsvWriter; +using LayerVolumeWriter = ActsExamples::NamedTupleCsvWriter; using BoundarySurface = Acts::BoundarySurfaceT; /// Write a single surface. diff --git a/Examples/Python/tests/root_file_hashes.txt b/Examples/Python/tests/root_file_hashes.txt index ad0c1584449..b7f412485f7 100644 --- a/Examples/Python/tests/root_file_hashes.txt +++ b/Examples/Python/tests/root_file_hashes.txt @@ -17,18 +17,6 @@ test_itk_seeding__particles.root: 0b6f4ad438010ac48803d48ed98e80b5e87d310bae6c2c test_itk_seeding__particles_simulation.root: ef0246069aa697019f28a8b270a68de95312cae5f2f2c74848566c3ce4f70363 test_propagation__propagation_steps.root: ba2e20d66f9f58850a9248bfaaafecbf0e8257020bb879b4572b783917f4d19b test_material_recording__geant4_material_tracks.root: c022b9362249b29f57a07926b20644e3ab4ab8ebcf03f773fbf46c446fc1a0a1 -test_truth_tracking_kalman[generic-0.0]__trackstates_fitter.root: 26640d70f7fab870e59666b0915569a6f8f82af68c63e5505548ffa9d24a3212 -test_truth_tracking_kalman[generic-0.0]__tracksummary_fitter.root: 496467c8305c52ef76f855f6eef00033f4428f785c6099b5ba60c1f3cae19dc3 -test_truth_tracking_kalman[generic-0.0]__performance_track_finder.root: ada9cda2ec3c648b144bdaa081d6eff923c80f3d484c4196006e847428cf67a8 -test_truth_tracking_kalman[generic-1000.0]__trackstates_fitter.root: 476e0dca91e5168f0574b86aea797dc22900fd456b3c3fb24d5f571b4be804fc -test_truth_tracking_kalman[generic-1000.0]__tracksummary_fitter.root: c8bdd0ccddeda38867517dd86665804bac2f3ab4bbb11a02a82dc725ee65e771 -test_truth_tracking_kalman[generic-1000.0]__performance_track_finder.root: ada9cda2ec3c648b144bdaa081d6eff923c80f3d484c4196006e847428cf67a8 -test_truth_tracking_kalman[odd-0.0]__trackstates_fitter.root: 56eeee0a03a2ba23fddc1dc56b935e4040803800c68f0f2cca1a35b40a74edb2 -test_truth_tracking_kalman[odd-0.0]__tracksummary_fitter.root: 3802b1bc849fe47bfa7ae72fb13d6bd592e0a82a97277bad12a8ceef59c00f64 -test_truth_tracking_kalman[odd-0.0]__performance_track_finder.root: 39aec6316cceb90e314e16b02947faa691c18f57c3a851a25e547a8fc05a4593 -test_truth_tracking_kalman[odd-1000.0]__trackstates_fitter.root: 72c79be1458c4f9c9a1661778c900f0875d257f2d391c4183a698825448919a1 -test_truth_tracking_kalman[odd-1000.0]__tracksummary_fitter.root: a53253b509b5779a5d856f8c09d76a499b217b55ba4b0e52d9076ffad726463f -test_truth_tracking_kalman[odd-1000.0]__performance_track_finder.root: 39aec6316cceb90e314e16b02947faa691c18f57c3a851a25e547a8fc05a4593 test_truth_tracking_gsf[generic]__trackstates_gsf.root: 1466671bee7b7cfffe90459d9aef316dcee104e6c32a2df4f2f11ea9f12ddc14 test_truth_tracking_gsf[generic]__tracksummary_gsf.root: b698e3d21eacc34fc8b0ce1d3fbe07405a4b8b549e07f0160573e64c3b401f04 test_truth_tracking_gsf[odd]__trackstates_gsf.root: 194198c9c9657b02192e573ba9969230663f179104e32e180101ffcd677b4745 @@ -85,23 +73,23 @@ test_exatrkx[cpu-torch]__performance_track_finding.root: 36b3045589c4c17c038dbc8 test_exatrkx[gpu-onnx]__performance_track_finding.root: 9090de10ffb1489d3f1993e2a3081a3038227e3e5c453e98a9a4f33ea3d6d817 test_exatrkx[gpu-torch]__performance_track_finding.root: 36b3045589c4c17c038dbc87943366f4af4440f7eea6887afb763871ac149b05 test_ML_Ambiguity_Solver__performance_ambiML.root: 284ff5c3a08c0b810938e4ac2f8ba8fe2babb17d4c202b624ed69fff731a9006 -test_truth_tracking_kalman[generic-False-0.0]__trackstates_fitter.root: a87b908ee14a3de3e8f894cb69dc011e23ec2de6fd92a71a91c367f18a7934f6 -test_truth_tracking_kalman[generic-False-0.0]__tracksummary_fitter.root: bf46a89e429fa77a380d5ee48babb8af2044196eff872825e84c0d4401357114 -test_truth_tracking_kalman[generic-False-1000.0]__trackstates_fitter.root: 5b945782c1ff59c7c30d3d2a23992292735bc3da27da6424309da9c9e9660322 -test_truth_tracking_kalman[generic-False-1000.0]__tracksummary_fitter.root: 055a74d2747d360398cc846cc2791204491528896de78cca66b188e3ff530dc1 -test_truth_tracking_kalman[generic-True-0.0]__trackstates_fitter.root: a87b908ee14a3de3e8f894cb69dc011e23ec2de6fd92a71a91c367f18a7934f6 -test_truth_tracking_kalman[generic-True-0.0]__tracksummary_fitter.root: bf46a89e429fa77a380d5ee48babb8af2044196eff872825e84c0d4401357114 -test_truth_tracking_kalman[generic-True-1000.0]__trackstates_fitter.root: 5b945782c1ff59c7c30d3d2a23992292735bc3da27da6424309da9c9e9660322 -test_truth_tracking_kalman[generic-True-1000.0]__tracksummary_fitter.root: 055a74d2747d360398cc846cc2791204491528896de78cca66b188e3ff530dc1 -test_truth_tracking_kalman[odd-False-0.0]__trackstates_fitter.root: 6e4a34638a4d76607597db1e02525f6c6a386ca44727cae255a0aa0c2b588c7f -test_truth_tracking_kalman[odd-False-0.0]__tracksummary_fitter.root: a45dbd0b6d221ec1b153f6e90d84601fe7a799134604c63be8e94bf8cd22af43 -test_truth_tracking_kalman[odd-False-1000.0]__trackstates_fitter.root: 7e0b19d1f8c818269925b95817b9c92c68af3b841fdbd21560aa55688ddec786 -test_truth_tracking_kalman[odd-False-1000.0]__tracksummary_fitter.root: 15a542955428dec0776c8317a33b7ef6c14858888ffc7406b00ac7044694b137 -test_truth_tracking_kalman[odd-True-0.0]__trackstates_fitter.root: 6e4a34638a4d76607597db1e02525f6c6a386ca44727cae255a0aa0c2b588c7f -test_truth_tracking_kalman[odd-True-0.0]__tracksummary_fitter.root: a45dbd0b6d221ec1b153f6e90d84601fe7a799134604c63be8e94bf8cd22af43 -test_truth_tracking_kalman[odd-True-1000.0]__trackstates_fitter.root: 7e0b19d1f8c818269925b95817b9c92c68af3b841fdbd21560aa55688ddec786 -test_truth_tracking_kalman[odd-True-1000.0]__tracksummary_fitter.root: 15a542955428dec0776c8317a33b7ef6c14858888ffc7406b00ac7044694b137 test_refitting[odd]__trackstates_gsf_refit.root: 1071ab66ec9a7d1ddddfb12beac8da6e9c489242f5fe2aee238b88aee0744823 test_refitting[odd]__tracksummary_gsf_refit.root: 16951808df6363d2acb99e385aec35ad723b634403ca0724a552ae9d3a2ae237 test_refitting[generic]__trackstates_gsf_refit.root: dbad2648b761e021bd21296755a0c73230da6e4796b306f6ac59424c40c9b80b test_refitting[generic]__tracksummary_gsf_refit.root: bf46a89e429fa77a380d5ee48babb8af2044196eff872825e84c0d4401357114 +test_truth_tracking_kalman[generic-False-0.0]__trackstates_kf.root: a87b908ee14a3de3e8f894cb69dc011e23ec2de6fd92a71a91c367f18a7934f6 +test_truth_tracking_kalman[generic-False-0.0]__tracksummary_kf.root: bf46a89e429fa77a380d5ee48babb8af2044196eff872825e84c0d4401357114 +test_truth_tracking_kalman[generic-False-1000.0]__trackstates_kf.root: 5b945782c1ff59c7c30d3d2a23992292735bc3da27da6424309da9c9e9660322 +test_truth_tracking_kalman[generic-False-1000.0]__tracksummary_kf.root: 055a74d2747d360398cc846cc2791204491528896de78cca66b188e3ff530dc1 +test_truth_tracking_kalman[generic-True-0.0]__trackstates_kf.root: a87b908ee14a3de3e8f894cb69dc011e23ec2de6fd92a71a91c367f18a7934f6 +test_truth_tracking_kalman[generic-True-0.0]__tracksummary_kf.root: bf46a89e429fa77a380d5ee48babb8af2044196eff872825e84c0d4401357114 +test_truth_tracking_kalman[generic-True-1000.0]__trackstates_kf.root: 5b945782c1ff59c7c30d3d2a23992292735bc3da27da6424309da9c9e9660322 +test_truth_tracking_kalman[generic-True-1000.0]__tracksummary_kf.root: 055a74d2747d360398cc846cc2791204491528896de78cca66b188e3ff530dc1 +test_truth_tracking_kalman[odd-False-0.0]__trackstates_kf.root: 6e4a34638a4d76607597db1e02525f6c6a386ca44727cae255a0aa0c2b588c7f +test_truth_tracking_kalman[odd-False-0.0]__tracksummary_kf.root: a45dbd0b6d221ec1b153f6e90d84601fe7a799134604c63be8e94bf8cd22af43 +test_truth_tracking_kalman[odd-False-1000.0]__trackstates_kf.root: 7e0b19d1f8c818269925b95817b9c92c68af3b841fdbd21560aa55688ddec786 +test_truth_tracking_kalman[odd-False-1000.0]__tracksummary_kf.root: 15a542955428dec0776c8317a33b7ef6c14858888ffc7406b00ac7044694b137 +test_truth_tracking_kalman[odd-True-0.0]__trackstates_kf.root: 6e4a34638a4d76607597db1e02525f6c6a386ca44727cae255a0aa0c2b588c7f +test_truth_tracking_kalman[odd-True-0.0]__tracksummary_kf.root: a45dbd0b6d221ec1b153f6e90d84601fe7a799134604c63be8e94bf8cd22af43 +test_truth_tracking_kalman[odd-True-1000.0]__trackstates_kf.root: 7e0b19d1f8c818269925b95817b9c92c68af3b841fdbd21560aa55688ddec786 +test_truth_tracking_kalman[odd-True-1000.0]__tracksummary_kf.root: 15a542955428dec0776c8317a33b7ef6c14858888ffc7406b00ac7044694b137 diff --git a/Examples/Python/tests/test_examples.py b/Examples/Python/tests/test_examples.py index bcb6b9695f2..3cf119b809f 100644 --- a/Examples/Python/tests/test_examples.py +++ b/Examples/Python/tests/test_examples.py @@ -537,9 +537,9 @@ def test_truth_tracking_kalman( seq = Sequencer(events=10, numThreads=1) root_files = [ - ("trackstates_fitter.root", "trackstates", 19), - ("tracksummary_fitter.root", "tracksummary", 10), - ("performance_track_fitter.root", None, -1), + ("trackstates_kf.root", "trackstates", 19), + ("tracksummary_kf.root", "tracksummary", 10), + ("performance_kf.root", None, -1), ] for fn, _, _ in root_files: @@ -572,7 +572,7 @@ def test_truth_tracking_kalman( ROOT.PyConfig.IgnoreCommandLineOptions = True ROOT.gROOT.SetBatch(True) - rf = ROOT.TFile.Open(str(tmp_path / "tracksummary_fitter.root")) + rf = ROOT.TFile.Open(str(tmp_path / "tracksummary_kf.root")) keys = [k.GetName() for k in rf.GetListOfKeys()] assert "tracksummary" in keys for entry in rf.Get("tracksummary"): diff --git a/Examples/Scripts/Python/truth_tracking_kalman.py b/Examples/Scripts/Python/truth_tracking_kalman.py index e0956b46bd5..714e0421e41 100755 --- a/Examples/Scripts/Python/truth_tracking_kalman.py +++ b/Examples/Scripts/Python/truth_tracking_kalman.py @@ -130,7 +130,7 @@ def runTruthTrackingKalman( inputTrackParticleMatching="track_particle_matching", inputSimHits="simhits", inputMeasurementSimHitsMap="measurement_simhits_map", - filePath=str(outputDir / "trackstates_fitter.root"), + filePath=str(outputDir / "trackstates_kf.root"), ) ) @@ -140,7 +140,7 @@ def runTruthTrackingKalman( inputTracks="tracks", inputParticles="truth_seeds_selected", inputTrackParticleMatching="track_particle_matching", - filePath=str(outputDir / "tracksummary_fitter.root"), + filePath=str(outputDir / "tracksummary_kf.root"), ) ) @@ -150,7 +150,7 @@ def runTruthTrackingKalman( inputTracks="tracks", inputParticles="truth_seeds_selected", inputTrackParticleMatching="track_particle_matching", - filePath=str(outputDir / "performance_track_fitter.root"), + filePath=str(outputDir / "performance_kf.root"), ) ) diff --git a/Tests/Benchmarks/CMakeLists.txt b/Tests/Benchmarks/CMakeLists.txt index 080be38eedc..4955febba09 100644 --- a/Tests/Benchmarks/CMakeLists.txt +++ b/Tests/Benchmarks/CMakeLists.txt @@ -32,3 +32,4 @@ add_benchmark(StraightLineStepper StraightLineStepperBenchmark.cpp) add_benchmark(QuickMath QuickMathBenchmark.cpp) add_benchmark(SympyStepper SympyStepperBenchmark.cpp) add_benchmark(Stepper StepperBenchmark.cpp) +add_benchmark(SourceLink SourceLinkBenchmark.cpp) diff --git a/Tests/Benchmarks/SourceLinkBenchmark.cpp b/Tests/Benchmarks/SourceLinkBenchmark.cpp new file mode 100644 index 00000000000..b65f89907e2 --- /dev/null +++ b/Tests/Benchmarks/SourceLinkBenchmark.cpp @@ -0,0 +1,136 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2024 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "Acts/EventData/VectorMultiTrajectory.hpp" +#include "Acts/Geometry/GeometryIdentifier.hpp" +#include "Acts/Tests/CommonHelpers/BenchmarkTools.hpp" + +#include +#include + +using namespace Acts; + +class BenchmarkSourceLink final { + public: + using Index = std::uint32_t; + + /// Construct from geometry identifier and index. + constexpr BenchmarkSourceLink(Acts::GeometryIdentifier gid, Index idx) + : m_geometryId(gid), m_index(idx) {} + + BenchmarkSourceLink() = default; + BenchmarkSourceLink(const BenchmarkSourceLink&) = default; + BenchmarkSourceLink(BenchmarkSourceLink&&) = default; + BenchmarkSourceLink& operator=(const BenchmarkSourceLink&) = default; + BenchmarkSourceLink& operator=(BenchmarkSourceLink&&) = default; + + /// Access the index. + constexpr Index index() const { return m_index; } + + Acts::GeometryIdentifier geometryId() const { return m_geometryId; } + + private: + Acts::GeometryIdentifier m_geometryId; + Index m_index = 0; + + friend bool operator==(const BenchmarkSourceLink& lhs, + const BenchmarkSourceLink& rhs) { + return (lhs.geometryId() == rhs.geometryId()) && + (lhs.m_index == rhs.m_index); + } + friend bool operator!=(const BenchmarkSourceLink& lhs, + const BenchmarkSourceLink& rhs) { + return !(lhs == rhs); + } +}; + +int main(int /*argc*/, char** /*argv[]*/) { + std::size_t n = 100000; + + VectorMultiTrajectory mtj; + + GeometryIdentifier gid; + gid.setVolume(5); + gid.setLayer(3); + gid.setSensitive(1); + + static_assert(sizeof(BenchmarkSourceLink) <= ACTS_SOURCELINK_SBO_SIZE); + + static_assert(std::is_trivially_move_constructible_v); + + BenchmarkSourceLink bsl{gid, 1234}; + + std::cout << "Creating source link" << std::endl; + auto source_link_construction = Acts::Test::microBenchmark( + [&]() { + SourceLink sl{bsl}; + return sl; + }, + n); + std::cout << " " << source_link_construction << std::endl; + + std::vector inputs; + inputs.reserve(n); + for (std::size_t i = 0; i < n; ++i) { + inputs.emplace_back(bsl); + } + + std::cout << "Copy construct source link" << std::endl; + auto copy_construct_source_link = Acts::Test::microBenchmark( + [&](const SourceLink& input) { + SourceLink copy{input}; + return copy; + }, + inputs); + std::cout << copy_construct_source_link << std::endl; + + std::cout << "Copy then move construct source link" << std::endl; + auto copy_move_construct_source_link = Acts::Test::microBenchmark( + [&](const SourceLink& input) { + SourceLink copy{input}; + SourceLink mv{std::move(copy)}; + return mv; + }, + inputs); + std::cout << copy_move_construct_source_link << std::endl; + + std::cout << "Optional assignment" << std::endl; + auto opt_assignment = Acts::Test::microBenchmark( + [&]() { + SourceLink sl{bsl}; + // ts.setUncalibratedSourceLink(std::move(sl)); + std::optional opt; + opt = std::move(sl); + return opt; + }, + n); + std::cout << opt_assignment << std::endl; + + // Measure track state creation + std::cout << "Create track state" << std::endl; + auto create_track_state = Acts::Test::microBenchmark( + [&]() { + auto ts = mtj.makeTrackState(TrackStatePropMask::None); + return ts; + }, + n / 10); + std::cout << create_track_state << std::endl; + + std::cout << "Assign source link to track state" << std::endl; + auto assign_source_link = Acts::Test::microBenchmark( + [&]() { + SourceLink sl{bsl}; + auto ts = mtj.makeTrackState(TrackStatePropMask::None); + ts.setUncalibratedSourceLink(std::move(sl)); + return ts; + }, + n / 10); + std::cout << assign_source_link << std::endl; + + return 0; +} diff --git a/Tests/UnitTests/Core/Navigation/NavigationStateUpdatersTests.cpp b/Tests/UnitTests/Core/Navigation/NavigationStateUpdatersTests.cpp index 7efecc884c9..3829fddb354 100644 --- a/Tests/UnitTests/Core/Navigation/NavigationStateUpdatersTests.cpp +++ b/Tests/UnitTests/Core/Navigation/NavigationStateUpdatersTests.cpp @@ -128,6 +128,8 @@ class TestAxis : public IAxis { ActsScalar getMax() const final { return 1.; } std::size_t getNBins() const final { return 1; }; + + void toStream(std::ostream& os) const final { os << "TextAxis"; } }; class MultiGrid1D { diff --git a/Tests/UnitTests/Core/Surfaces/CylinderSurfaceTests.cpp b/Tests/UnitTests/Core/Surfaces/CylinderSurfaceTests.cpp index 5d0bb4c3d5c..c36b637c50b 100644 --- a/Tests/UnitTests/Core/Surfaces/CylinderSurfaceTests.cpp +++ b/Tests/UnitTests/Core/Surfaces/CylinderSurfaceTests.cpp @@ -21,6 +21,7 @@ #include "Acts/Surfaces/Surface.hpp" #include "Acts/Surfaces/SurfaceBounds.hpp" #include "Acts/Surfaces/SurfaceMergingException.hpp" +#include "Acts/Tests/CommonHelpers/DetectorElementStub.hpp" #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" #include "Acts/Utilities/BinningType.hpp" #include "Acts/Utilities/Helpers.hpp" @@ -348,6 +349,18 @@ BOOST_AUTO_TEST_CASE(CylinderSurfaceBinningPosition) { BOOST_AUTO_TEST_SUITE(CylinderSurfaceMerging) +BOOST_AUTO_TEST_CASE(InvalidDetectorElement) { + DetectorElementStub detElem; + + auto bounds = std::make_shared(100_mm, 100_mm); + auto cyl1 = Surface::makeShared(bounds, detElem); + auto cyl2 = Surface::makeShared(bounds, detElem); + + BOOST_CHECK_THROW( + cyl1->mergedWith(*cyl2, Acts::BinningValue::binR, false, *logger), + SurfaceMergingException); +} + BOOST_DATA_TEST_CASE(IncompatibleZDirection, (boost::unit_test::data::xrange(-135, 180, 45) * boost::unit_test::data::make(Vector3{0_mm, 0_mm, 0_mm}, @@ -366,36 +379,28 @@ BOOST_DATA_TEST_CASE(IncompatibleZDirection, base * Translation3{Vector3::UnitZ() * 200_mm}, 30_mm, 100_mm); BOOST_CHECK_THROW( - cyl->mergedWith(testContext, *cyl2, Acts::BinningValue::binPhi, *logger), + cyl->mergedWith(*cyl2, Acts::BinningValue::binPhi, false, *logger), SurfaceMergingException); auto cylShiftedXy = Surface::makeShared( base * Translation3{Vector3{1_mm, 2_mm, 200_mm}}, 30_mm, 100_mm); - BOOST_CHECK_THROW(cyl->mergedWith(testContext, *cylShiftedXy, - Acts::BinningValue::binZ, *logger), - SurfaceMergingException); - - auto cylRotatedZ = Surface::makeShared( - base * AngleAxis3{10_degree, Vector3::UnitZ()} * - Translation3{Vector3::UnitZ() * 200_mm}, - 30_mm, 100_mm); - BOOST_CHECK_THROW(cyl->mergedWith(testContext, *cylRotatedZ, - Acts::BinningValue::binZ, *logger), - SurfaceMergingException); + BOOST_CHECK_THROW( + cyl->mergedWith(*cylShiftedXy, Acts::BinningValue::binZ, false, *logger), + SurfaceMergingException); auto cylRotatedX = Surface::makeShared( base * AngleAxis3{10_degree, Vector3::UnitX()} * Translation3{Vector3::UnitZ() * 200_mm}, 30_mm, 100_mm); - BOOST_CHECK_THROW(cyl->mergedWith(testContext, *cylRotatedX, - Acts::BinningValue::binZ, *logger), - SurfaceMergingException); + BOOST_CHECK_THROW( + cyl->mergedWith(*cylRotatedX, Acts::BinningValue::binZ, false, *logger), + SurfaceMergingException); // Cylinder with different radius auto cyl3 = Surface::makeShared( base * Translation3{Vector3::UnitZ() * 200_mm}, 35_mm, 100_mm); BOOST_CHECK_THROW( - cyl->mergedWith(testContext, *cyl3, Acts::BinningValue::binZ, *logger), + cyl->mergedWith(*cyl3, Acts::BinningValue::binZ, false, *logger), SurfaceMergingException); // Cylinder with bevel @@ -403,28 +408,46 @@ BOOST_DATA_TEST_CASE(IncompatibleZDirection, base * Translation3{Vector3::UnitZ() * 200_mm}, 30_mm, 100_mm, M_PI, 0, M_PI / 8.0); BOOST_CHECK_THROW( - cyl->mergedWith(testContext, *cyl4, Acts::BinningValue::binZ, *logger), + cyl->mergedWith(*cyl4, Acts::BinningValue::binZ, false, *logger), SurfaceMergingException); auto cyl5 = Surface::makeShared( base * Translation3{Vector3::UnitZ() * 200_mm}, 30_mm, 100_mm, M_PI, 0, 0, M_PI / 8.0); BOOST_CHECK_THROW( - cyl->mergedWith(testContext, *cyl5, Acts::BinningValue::binZ, *logger), + cyl->mergedWith(*cyl5, Acts::BinningValue::binZ, false, *logger), SurfaceMergingException); // Cylinder with overlap in z auto cyl6 = Surface::makeShared( base * Translation3{Vector3::UnitZ() * 150_mm}, 30_mm, 100_mm); BOOST_CHECK_THROW( - cyl->mergedWith(testContext, *cyl6, Acts::BinningValue::binZ, *logger), + cyl->mergedWith(*cyl6, Acts::BinningValue::binZ, false, *logger), SurfaceMergingException); // Cylinder with gap in z auto cyl7 = Surface::makeShared( base * Translation3{Vector3::UnitZ() * 250_mm}, 30_mm, 100_mm); BOOST_CHECK_THROW( - cyl->mergedWith(testContext, *cyl7, Acts::BinningValue::binZ, *logger), + cyl->mergedWith(*cyl7, Acts::BinningValue::binZ, false, *logger), + SurfaceMergingException); + + // Cylinder with phi sector and relative z rotation + auto cyl8 = Surface::makeShared( + base * AngleAxis3(14_degree, Vector3::UnitZ()) * + Translation3{Vector3::UnitZ() * 200_mm}, + 30_mm, 100_mm, 10_degree, 40_degree); + BOOST_CHECK_THROW( + cyl->mergedWith(*cyl8, Acts::BinningValue::binZ, false, *logger), + SurfaceMergingException); + + auto cylPhi1 = Surface::makeShared(Transform3::Identity(), + 30_mm, 100_mm, 45_degree); + auto cylPhi2 = Surface::makeShared( + Transform3{Translation3{Vector3::UnitZ() * 150_mm}}, 30_mm, 50_mm, + 55_degree); + BOOST_CHECK_THROW( + cylPhi1->mergedWith(*cylPhi2, Acts::BinningValue::binZ, false, *logger), SurfaceMergingException); } @@ -442,24 +465,52 @@ BOOST_DATA_TEST_CASE(ZDirection, auto cyl = Surface::makeShared(base, 30_mm, 100_mm); auto cyl2 = Surface::makeShared( - base * Translation3{Vector3::UnitZ() * 200_mm}, 30_mm, 100_mm); + base * AngleAxis3(14_degree, Vector3::UnitZ()) * + Translation3{Vector3::UnitZ() * 200_mm}, + 30_mm, 100_mm); - auto cyl3 = - cyl->mergedWith(testContext, *cyl2, Acts::BinningValue::binZ, *logger); + auto [cyl3, reversed] = + cyl->mergedWith(*cyl2, Acts::BinningValue::binZ, false, *logger); BOOST_REQUIRE_NE(cyl3, nullptr); + BOOST_CHECK(!reversed); - auto cyl3Reversed = - cyl2->mergedWith(testContext, *cyl, Acts::BinningValue::binZ, *logger); + auto [cyl3Reversed, reversed2] = + cyl2->mergedWith(*cyl, Acts::BinningValue::binZ, false, *logger); BOOST_REQUIRE_NE(cyl3Reversed, nullptr); - BOOST_CHECK(*cyl3 == *cyl3Reversed); + BOOST_CHECK(cyl3->bounds() == cyl3Reversed->bounds()); + BOOST_CHECK(reversed2); auto bounds = cyl3->bounds(); BOOST_CHECK_EQUAL(bounds.get(CylinderBounds::eR), 30_mm); BOOST_CHECK_EQUAL(bounds.get(CylinderBounds::eHalfLengthZ), 200_mm); - - Transform3 expected = base * Translation3{Vector3::UnitZ() * 100_mm}; - BOOST_CHECK_EQUAL(expected.matrix(), cyl3->transform(testContext).matrix()); + BOOST_CHECK_EQUAL(bounds.get(CylinderBounds::eAveragePhi), 0_degree); + BOOST_CHECK_EQUAL(bounds.get(CylinderBounds::eHalfPhiSector), 180_degree); + + // Rotation in z depends on the ordering, the left side "wins" + Transform3 expected12 = base * Translation3{Vector3::UnitZ() * 100_mm}; + BOOST_CHECK_EQUAL(expected12.matrix(), cyl3->transform(testContext).matrix()); + + Transform3 expected21 = base * AngleAxis3(14_degree, Vector3::UnitZ()) * + Translation3{Vector3::UnitZ() * 100_mm}; + CHECK_CLOSE_OR_SMALL(cyl3Reversed->transform(testContext).matrix(), + expected21.matrix(), 1e-6, 1e-10); + + auto cylPhi1 = Surface::makeShared(Transform3::Identity(), + 30_mm, 100_mm, 45_degree); + auto cylPhi2 = Surface::makeShared( + Transform3{Translation3{Vector3::UnitZ() * 150_mm}}, 30_mm, 50_mm, + 45_degree); + + auto [cylPhi12, reversedPhy12] = + cylPhi1->mergedWith(*cylPhi2, Acts::BinningValue::binZ, false, *logger); + + BOOST_REQUIRE_NE(cylPhi12, nullptr); + auto boundsPhi12 = cylPhi12->bounds(); + BOOST_CHECK_EQUAL(boundsPhi12.get(CylinderBounds::eR), 30_mm); + BOOST_CHECK_EQUAL(boundsPhi12.get(CylinderBounds::eHalfLengthZ), 150_mm); + BOOST_CHECK_EQUAL(boundsPhi12.get(CylinderBounds::eAveragePhi), 0_degree); + BOOST_CHECK_EQUAL(boundsPhi12.get(CylinderBounds::eHalfPhiSector), 45_degree); } BOOST_DATA_TEST_CASE(IncompatibleRPhiDirection, @@ -485,24 +536,31 @@ BOOST_DATA_TEST_CASE(IncompatibleRPhiDirection, // Cylinder with overlap in phi auto cylPhi2 = Surface::makeShared(base, 30_mm, 100_mm, 45_degree, a(85_degree)); - BOOST_CHECK_THROW(cylPhi->mergedWith(testContext, *cylPhi2, - Acts::BinningValue::binRPhi, *logger), - SurfaceMergingException); + BOOST_CHECK_THROW( + cylPhi->mergedWith(*cylPhi2, Acts::BinningValue::binRPhi, false, *logger), + SurfaceMergingException); // Cylinder with gap in phi auto cylPhi3 = Surface::makeShared(base, 30_mm, 100_mm, 45_degree, a(105_degree)); - BOOST_CHECK_THROW(cylPhi->mergedWith(testContext, *cylPhi3, - Acts::BinningValue::binRPhi, *logger), - SurfaceMergingException); + BOOST_CHECK_THROW( + cylPhi->mergedWith(*cylPhi3, Acts::BinningValue::binRPhi, false, *logger), + SurfaceMergingException); // Cylinder with a z shift auto cylPhi4 = Surface::makeShared( base * Translation3{Vector3::UnitZ() * 20_mm}, 30_mm, 100_mm, 45_degree, a(95_degree)); - BOOST_CHECK_THROW(cylPhi->mergedWith(testContext, *cylPhi4, - Acts::BinningValue::binRPhi, *logger), - SurfaceMergingException); + BOOST_CHECK_THROW( + cylPhi->mergedWith(*cylPhi4, Acts::BinningValue::binRPhi, false, *logger), + SurfaceMergingException); + + // Test phi sector with different z halflengths + auto cylPhi5 = Surface::makeShared(base, 30_mm, 110_mm, + 45_degree, a(95_degree)); + BOOST_CHECK_THROW( + cylPhi->mergedWith(*cylPhi5, Acts::BinningValue::binRPhi, false, *logger), + SurfaceMergingException); } BOOST_DATA_TEST_CASE(RPhiDirection, @@ -521,50 +579,164 @@ BOOST_DATA_TEST_CASE(RPhiDirection, return detail::radian_sym(v + phiShift * 1_degree); }; - auto cyl = Surface::makeShared(base, 30_mm, 100_mm, - 10_degree, a(40_degree)); - auto cyl2 = Surface::makeShared(base, 30_mm, 100_mm, - 45_degree, a(95_degree)); - - auto cyl3 = - cyl->mergedWith(testContext, *cyl2, Acts::BinningValue::binRPhi, *logger); - BOOST_REQUIRE_NE(cyl3, nullptr); - BOOST_CHECK_EQUAL(base.matrix(), cyl3->transform(testContext).matrix()); + BOOST_TEST_CONTEXT("Internal rotation") { + auto cyl = Surface::makeShared(base, 30_mm, 100_mm, + 10_degree, a(40_degree)); + auto cyl2 = Surface::makeShared(base, 30_mm, 100_mm, + 45_degree, a(95_degree)); + + auto [cyl3, reversed] = + cyl->mergedWith(*cyl2, Acts::BinningValue::binRPhi, false, *logger); + BOOST_REQUIRE_NE(cyl3, nullptr); + BOOST_CHECK_EQUAL(base.matrix(), cyl3->transform(testContext).matrix()); + BOOST_CHECK(reversed); + + auto [cyl3Reversed, reversed2] = + cyl2->mergedWith(*cyl, Acts::BinningValue::binRPhi, false, *logger); + BOOST_REQUIRE_NE(cyl3Reversed, nullptr); + BOOST_CHECK(*cyl3 == *cyl3Reversed); + BOOST_CHECK(!reversed2); + + const auto& bounds = cyl3->bounds(); + + BOOST_CHECK_SMALL( + detail::difference_periodic(bounds.get(CylinderBounds::eAveragePhi), + a(85_degree), 2 * M_PI), + 1e-6); + BOOST_CHECK_CLOSE(bounds.get(CylinderBounds::eHalfPhiSector), 55_degree, + 0.1); + + auto cyl4 = Surface::makeShared(base, 30_mm, 100_mm, + 20_degree, a(170_degree)); + auto cyl5 = Surface::makeShared(base, 30_mm, 100_mm, + 10_degree, a(-160_degree)); + auto [cyl45, reversed45] = + cyl4->mergedWith(*cyl5, Acts::BinningValue::binRPhi, false, *logger); + BOOST_REQUIRE_NE(cyl45, nullptr); + BOOST_CHECK_EQUAL(base.matrix(), cyl45->transform(testContext).matrix()); + BOOST_CHECK(reversed45); + + auto [cyl54, reversed54] = + cyl5->mergedWith(*cyl4, Acts::BinningValue::binRPhi, false, *logger); + BOOST_REQUIRE_NE(cyl54, nullptr); + BOOST_CHECK(!reversed54); + + BOOST_CHECK(*cyl54 == *cyl45); + + BOOST_CHECK_SMALL(detail::difference_periodic( + cyl45->bounds().get(CylinderBounds::eAveragePhi), + a(180_degree), 2 * M_PI), + 1e-6); + BOOST_CHECK_CLOSE(cyl45->bounds().get(CylinderBounds::eHalfPhiSector), + 30_degree, 1e-6); + + auto cyl6 = Surface::makeShared(base, 30_mm, 100_mm, + 90_degree, a(90_degree)); + auto cyl7 = Surface::makeShared(base, 30_mm, 100_mm, + 90_degree, a(-90_degree)); + + auto [cyl67, reversed67] = + cyl6->mergedWith(*cyl7, Acts::BinningValue::binRPhi, false, *logger); + BOOST_REQUIRE_NE(cyl67, nullptr); + BOOST_CHECK_EQUAL(base.matrix(), cyl67->transform(testContext).matrix()); + + auto [cyl76, reversed76] = + cyl7->mergedWith(*cyl6, Acts::BinningValue::binRPhi, false, *logger); + BOOST_REQUIRE_NE(cyl76, nullptr); + BOOST_CHECK_EQUAL(base.matrix(), cyl76->transform(testContext).matrix()); + + // The ordering in this case is effectively arbitrary, you get the ordering + // you put in + BOOST_CHECK(!reversed67); + BOOST_CHECK(!reversed76); + + BOOST_CHECK_SMALL(detail::difference_periodic( + cyl67->bounds().get(CylinderBounds::eAveragePhi), + a(180_degree), 2 * M_PI), + 1e-6); + BOOST_CHECK_CLOSE(cyl67->bounds().get(CylinderBounds::eHalfPhiSector), + 180_degree, 1e-6); + } - auto cyl3Reversed = - cyl2->mergedWith(testContext, *cyl, Acts::BinningValue::binRPhi, *logger); - BOOST_REQUIRE_NE(cyl3Reversed, nullptr); - BOOST_CHECK(*cyl3 == *cyl3Reversed); - - const auto& bounds = cyl3->bounds(); - - BOOST_CHECK_SMALL( - detail::difference_periodic(bounds.get(CylinderBounds::eAveragePhi), - a(85_degree), 2 * M_PI), - 1e-6); - BOOST_CHECK_CLOSE(bounds.get(CylinderBounds::eHalfPhiSector), 55_degree, 0.1); - - auto cyl4 = Surface::makeShared(base, 30_mm, 100_mm, - 20_degree, a(170_degree)); - auto cyl5 = Surface::makeShared(base, 30_mm, 100_mm, - 10_degree, a(-160_degree)); - auto cyl45 = cyl4->mergedWith(testContext, *cyl5, Acts::BinningValue::binRPhi, - *logger); - BOOST_REQUIRE_NE(cyl45, nullptr); - BOOST_CHECK_EQUAL(base.matrix(), cyl45->transform(testContext).matrix()); - - auto cyl54 = cyl5->mergedWith(testContext, *cyl4, Acts::BinningValue::binRPhi, - *logger); - BOOST_REQUIRE_NE(cyl54, nullptr); - - BOOST_CHECK(*cyl54 == *cyl45); - - BOOST_CHECK_SMALL(detail::difference_periodic( - cyl45->bounds().get(CylinderBounds::eAveragePhi), - a(180_degree), 2 * M_PI), - 1e-6); - BOOST_CHECK_CLOSE(cyl45->bounds().get(CylinderBounds::eHalfPhiSector), - 30_degree, 0.1); + BOOST_TEST_CONTEXT("External rotation") { + Transform3 trf1 = base * AngleAxis3(a(40_degree), Vector3::UnitZ()); + auto cyl1 = Surface::makeShared(trf1, 30_mm, 100_mm, + 10_degree, 0_degree); + + Transform3 trf2 = base * AngleAxis3(a(95_degree), Vector3::UnitZ()); + auto cyl2 = Surface::makeShared(trf2, 30_mm, 100_mm, + 45_degree, 0_degree); + + auto [cyl3, reversed] = + cyl1->mergedWith(*cyl2, Acts::BinningValue::binRPhi, true, *logger); + + BOOST_REQUIRE_NE(cyl3, nullptr); + Transform3 trfExpected12 = + base * AngleAxis3(a(85_degree), Vector3::UnitZ()); + CHECK_CLOSE_OR_SMALL(cyl3->transform(testContext).matrix(), + trfExpected12.matrix(), 1e-6, 1e-10); + BOOST_CHECK(reversed); + + BOOST_CHECK_EQUAL(cyl3->bounds().get(CylinderBounds::eAveragePhi), 0); + BOOST_CHECK_CLOSE(cyl3->bounds().get(CylinderBounds::eHalfPhiSector), + 55_degree, 1e-6); + + Transform3 trf4 = base * AngleAxis3(a(170_degree), Vector3::UnitZ()); + auto cyl4 = Surface::makeShared(trf4, 30_mm, 100_mm, + 20_degree, 0_degree); + Transform3 trf5 = base * AngleAxis3(a(-160_degree), Vector3::UnitZ()); + auto cyl5 = Surface::makeShared(trf5, 30_mm, 100_mm, + 10_degree, 0_degree); + auto [cyl45, reversed45] = + cyl4->mergedWith(*cyl5, Acts::BinningValue::binRPhi, true, *logger); + BOOST_REQUIRE_NE(cyl45, nullptr); + Transform3 trfExpected45 = + base * AngleAxis3(a(180_degree), Vector3::UnitZ()); + CHECK_CLOSE_OR_SMALL(cyl45->transform(testContext).matrix(), + trfExpected45.matrix(), 1e-6, 1e-10); + BOOST_CHECK(reversed45); + + auto [cyl54, reversed54] = + cyl5->mergedWith(*cyl4, Acts::BinningValue::binRPhi, true, *logger); + BOOST_REQUIRE_NE(cyl54, nullptr); + BOOST_CHECK(!reversed54); + + BOOST_CHECK(*cyl54 == *cyl45); + + BOOST_CHECK_EQUAL(cyl45->bounds().get(CylinderBounds::eAveragePhi), 0); + BOOST_CHECK_CLOSE(cyl45->bounds().get(CylinderBounds::eHalfPhiSector), + 30_degree, 1e-6); + + Transform3 trf6 = base * AngleAxis3(a(90_degree), Vector3::UnitZ()); + auto cyl6 = Surface::makeShared(trf6, 30_mm, 100_mm, + 90_degree, 0_degree); + Transform3 trf7 = base * AngleAxis3(a(-90_degree), Vector3::UnitZ()); + auto cyl7 = Surface::makeShared(trf7, 30_mm, 100_mm, + 90_degree, 0_degree); + + auto [cyl67, reversed67] = + cyl6->mergedWith(*cyl7, Acts::BinningValue::binRPhi, true, *logger); + BOOST_REQUIRE_NE(cyl67, nullptr); + Transform3 expected67 = trf6 * AngleAxis3(90_degree, Vector3::UnitZ()); + CHECK_CLOSE_OR_SMALL(cyl67->transform(testContext).matrix(), + expected67.matrix(), 1e-6, 1e-10); + + auto [cyl76, reversed76] = + cyl7->mergedWith(*cyl6, Acts::BinningValue::binRPhi, true, *logger); + BOOST_REQUIRE_NE(cyl76, nullptr); + Transform3 expected76 = trf7 * AngleAxis3(90_degree, Vector3::UnitZ()); + CHECK_CLOSE_OR_SMALL(cyl76->transform(testContext).matrix(), + expected76.matrix(), 1e-6, 1e-10); + + // The ordering in this case is effectively arbitrary, you get the ordering + // you put in + BOOST_CHECK(!reversed67); + BOOST_CHECK(!reversed76); + + BOOST_CHECK_EQUAL(cyl67->bounds().get(CylinderBounds::eAveragePhi), 0); + BOOST_CHECK_CLOSE(cyl67->bounds().get(CylinderBounds::eHalfPhiSector), + 180_degree, 0.1); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Core/Surfaces/DiscSurfaceTests.cpp b/Tests/UnitTests/Core/Surfaces/DiscSurfaceTests.cpp index b50a8cfb81c..a33630546b2 100644 --- a/Tests/UnitTests/Core/Surfaces/DiscSurfaceTests.cpp +++ b/Tests/UnitTests/Core/Surfaces/DiscSurfaceTests.cpp @@ -422,11 +422,26 @@ BOOST_AUTO_TEST_CASE(IncompatibleBounds) { Surface::makeShared(base, 20_mm, 40_mm, 30_mm, 100_mm); BOOST_CHECK_THROW( - discRadial->mergedWith(tgContext, *discTrap, BinningValue::binR, *logger), + discRadial->mergedWith(*discTrap, BinningValue::binR, false, *logger), + SurfaceMergingException); BOOST_CHECK_THROW( - discTrap2->mergedWith(tgContext, *discTrap, BinningValue::binR, *logger), + discTrap2->mergedWith(*discTrap, BinningValue::binR, false, *logger), + SurfaceMergingException); +} + +BOOST_AUTO_TEST_CASE(InvalidDetectorElement) { + DetectorElementStub detElem; + + auto bounds1 = std::make_shared(30_mm, 100_mm); + auto disc1 = Surface::makeShared(bounds1, detElem); + + auto bounds2 = std::make_shared(100_mm, 150_mm); + auto disc2 = Surface::makeShared(bounds2, detElem); + + BOOST_CHECK_THROW( + disc1->mergedWith(*disc2, BinningValue::binR, false, *logger), SurfaceMergingException); } @@ -447,38 +462,51 @@ BOOST_DATA_TEST_CASE(IncompatibleRDirection, // Disc with overlap in r auto discOverlap = makeDisc(base, 90_mm, 150_mm); - BOOST_CHECK_THROW(disc->mergedWith(tgContext, *discOverlap, - Acts::BinningValue::binR, *logger), - SurfaceMergingException); + BOOST_CHECK_THROW( + disc->mergedWith(*discOverlap, Acts::BinningValue::binR, false, *logger), + SurfaceMergingException); // Disc with gap in r auto discGap = makeDisc(base, 110_mm, 150_mm); BOOST_CHECK_THROW( - disc->mergedWith(tgContext, *discGap, Acts::BinningValue::binR, *logger), + disc->mergedWith(*discGap, Acts::BinningValue::binR, false, *logger), SurfaceMergingException); auto discShiftedZ = Surface::makeShared( base * Translation3{Vector3::UnitZ() * 10_mm}, 100_mm, 150_mm); - BOOST_CHECK_THROW(disc->mergedWith(tgContext, *discShiftedZ, - Acts::BinningValue::binR, *logger), - SurfaceMergingException); + BOOST_CHECK_THROW( + disc->mergedWith(*discShiftedZ, Acts::BinningValue::binR, false, *logger), + SurfaceMergingException); auto discShiftedXy = makeDisc( base * Translation3{Vector3{1_mm, 2_mm, 200_mm}}, 100_mm, 150_mm); - BOOST_CHECK_THROW(disc->mergedWith(tgContext, *discShiftedXy, - Acts::BinningValue::binZ, *logger), + BOOST_CHECK_THROW(disc->mergedWith(*discShiftedXy, Acts::BinningValue::binZ, + false, *logger), SurfaceMergingException); - auto discRotatedZ = - makeDisc(base * AngleAxis3{10_degree, Vector3::UnitZ()}, 100_mm, 150_mm); - BOOST_CHECK_THROW(disc->mergedWith(tgContext, *discRotatedZ, - Acts::BinningValue::binR, *logger), - SurfaceMergingException); + auto discRotatedZ = makeDisc(base * AngleAxis3{10_degree, Vector3::UnitZ()}, + 100_mm, 150_mm, 60_degree, 0_degree); + BOOST_CHECK_THROW( + disc->mergedWith(*discRotatedZ, Acts::BinningValue::binR, false, *logger), + SurfaceMergingException); + auto discRotatedX = makeDisc(base * AngleAxis3{10_degree, Vector3::UnitX()}, 100_mm, 150_mm); - BOOST_CHECK_THROW(disc->mergedWith(tgContext, *discRotatedX, - Acts::BinningValue::binR, *logger), - SurfaceMergingException); + BOOST_CHECK_THROW( + disc->mergedWith(*discRotatedX, Acts::BinningValue::binR, false, *logger), + SurfaceMergingException); + + // Test not same phi sector + auto discPhi1 = makeDisc(base, 30_mm, 100_mm, 10_degree, 40_degree); + auto discPhi2 = makeDisc(base, 100_mm, 160_mm, 20_degree, 40_degree); + auto discPhi3 = makeDisc(base, 100_mm, 160_mm, 10_degree, 50_degree); + BOOST_CHECK_THROW( + discPhi1->mergedWith(*discPhi2, BinningValue::binR, false, *logger), + SurfaceMergingException); + + BOOST_CHECK_THROW( + discPhi1->mergedWith(*discPhi3, BinningValue::binR, false, *logger), + SurfaceMergingException); } BOOST_DATA_TEST_CASE(RDirection, @@ -494,16 +522,19 @@ BOOST_DATA_TEST_CASE(RDirection, auto disc = makeDisc(base, 30_mm, 100_mm); - auto disc2 = makeDisc(base, 100_mm, 150_mm); + auto disc2 = + makeDisc(base * AngleAxis3(14_degree, Vector3::UnitZ()), 100_mm, 150_mm); - auto disc3 = - disc->mergedWith(tgContext, *disc2, Acts::BinningValue::binR, *logger); + auto [disc3, reversed] = + disc->mergedWith(*disc2, Acts::BinningValue::binR, false, *logger); BOOST_REQUIRE_NE(disc3, nullptr); + BOOST_CHECK(!reversed); - auto disc3Reversed = - disc2->mergedWith(tgContext, *disc, Acts::BinningValue::binR, *logger); + auto [disc3Reversed, reversed2] = + disc2->mergedWith(*disc, Acts::BinningValue::binR, false, *logger); BOOST_REQUIRE_NE(disc3Reversed, nullptr); - BOOST_CHECK(*disc3 == *disc3Reversed); + BOOST_CHECK(disc3->bounds() == disc3Reversed->bounds()); + BOOST_CHECK(reversed2); const auto* bounds = dynamic_cast(&disc3->bounds()); BOOST_REQUIRE_NE(bounds, nullptr); @@ -513,6 +544,29 @@ BOOST_DATA_TEST_CASE(RDirection, // Disc did not move BOOST_CHECK_EQUAL(base.matrix(), disc3->transform(tgContext).matrix()); + + // Rotation in z depends on the ordering, the left side "wins" + Transform3 expected12 = base; + BOOST_CHECK_EQUAL(expected12.matrix(), disc3->transform(tgContext).matrix()); + + Transform3 expected21 = base * AngleAxis3(14_degree, Vector3::UnitZ()); + CHECK_CLOSE_OR_SMALL(disc3Reversed->transform(tgContext).matrix(), + expected21.matrix(), 1e-6, 1e-10); + + // Test r merging with phi sectors (matching) + auto discPhi1 = makeDisc(base, 30_mm, 100_mm, 10_degree, 40_degree); + auto discPhi2 = makeDisc(base, 100_mm, 160_mm, 10_degree, 40_degree); + auto [discPhi12, reversedPhi12] = + discPhi1->mergedWith(*discPhi2, BinningValue::binR, false, *logger); + BOOST_REQUIRE_NE(discPhi12, nullptr); + + const auto* boundsPhi12 = + dynamic_cast(&discPhi12->bounds()); + BOOST_REQUIRE_NE(boundsPhi12, nullptr); + + BOOST_CHECK_EQUAL(boundsPhi12->get(RadialBounds::eMinR), 30_mm); + BOOST_CHECK_EQUAL(boundsPhi12->get(RadialBounds::eMaxR), 160_mm); + BOOST_CHECK_EQUAL(boundsPhi12->get(RadialBounds::eHalfPhiSector), 10_degree); } BOOST_DATA_TEST_CASE(IncompatiblePhiDirection, @@ -536,27 +590,27 @@ BOOST_DATA_TEST_CASE(IncompatiblePhiDirection, // Disc with overlap in phi auto discPhi2 = makeDisc(base, 30_mm, 100_mm, 45_degree, a(85_degree)); - BOOST_CHECK_THROW(discPhi->mergedWith(tgContext, *discPhi2, - Acts::BinningValue::binPhi, *logger), + BOOST_CHECK_THROW(discPhi->mergedWith(*discPhi2, Acts::BinningValue::binPhi, + false, *logger), SurfaceMergingException); // Disc with gap in phi auto discPhi3 = makeDisc(base, 30_mm, 100_mm, 45_degree, a(105_degree)); - BOOST_CHECK_THROW(discPhi->mergedWith(tgContext, *discPhi3, - Acts::BinningValue::binPhi, *logger), + BOOST_CHECK_THROW(discPhi->mergedWith(*discPhi3, Acts::BinningValue::binPhi, + false, *logger), SurfaceMergingException); // Disc with a z shift auto discPhi4 = makeDisc(base * Translation3{Vector3::UnitZ() * 20_mm}, 30_mm, 100_mm, 45_degree, a(95_degree)); - BOOST_CHECK_THROW(discPhi->mergedWith(tgContext, *discPhi4, - Acts::BinningValue::binPhi, *logger), + BOOST_CHECK_THROW(discPhi->mergedWith(*discPhi4, Acts::BinningValue::binPhi, + false, *logger), SurfaceMergingException); // Disc with different r bounds: could be merged in r but not in phi auto discPhi5 = makeDisc(base, 100_mm, 150_mm, 45_degree, a(95_degree)); - BOOST_CHECK_THROW(discPhi->mergedWith(tgContext, *discPhi5, - Acts::BinningValue::binPhi, *logger), + BOOST_CHECK_THROW(discPhi->mergedWith(*discPhi5, Acts::BinningValue::binPhi, + false, *logger), SurfaceMergingException); } @@ -576,50 +630,177 @@ BOOST_DATA_TEST_CASE(PhiDirection, return detail::radian_sym(v + phiShift * 1_degree); }; - auto disc = makeDisc(base, 30_mm, 100_mm, 10_degree, a(40_degree)); - auto disc2 = makeDisc(base, 30_mm, 100_mm, 45_degree, a(95_degree)); - - auto disc3 = - disc->mergedWith(tgContext, *disc2, Acts::BinningValue::binPhi, *logger); - BOOST_REQUIRE_NE(disc3, nullptr); - BOOST_CHECK_EQUAL(base.matrix(), disc3->transform(tgContext).matrix()); - - auto disc3Reversed = - disc2->mergedWith(tgContext, *disc, Acts::BinningValue::binPhi, *logger); - BOOST_REQUIRE_NE(disc3Reversed, nullptr); - BOOST_CHECK(*disc3 == *disc3Reversed); - - const auto* bounds = dynamic_cast(&disc3->bounds()); - BOOST_REQUIRE_NE(bounds, nullptr); - - BOOST_CHECK_SMALL( - detail::difference_periodic(bounds->get(RadialBounds::eAveragePhi), - a(85_degree), 2 * M_PI), - 1e-6); - BOOST_CHECK_CLOSE(bounds->get(RadialBounds::eHalfPhiSector), 55_degree, 0.1); - - auto disc4 = makeDisc(base, 30_mm, 100_mm, 20_degree, a(170_degree)); - auto disc5 = makeDisc(base, 30_mm, 100_mm, 10_degree, a(-160_degree)); - auto disc45 = - disc4->mergedWith(tgContext, *disc5, Acts::BinningValue::binPhi, *logger); - BOOST_REQUIRE_NE(disc45, nullptr); - BOOST_CHECK_EQUAL(base.matrix(), disc45->transform(tgContext).matrix()); - - auto disc54 = - disc5->mergedWith(tgContext, *disc4, Acts::BinningValue::binPhi, *logger); - BOOST_REQUIRE_NE(disc54, nullptr); - - BOOST_CHECK(*disc54 == *disc45); - - const auto* bounds45 = dynamic_cast(&disc45->bounds()); - BOOST_REQUIRE_NE(bounds, nullptr); + BOOST_TEST_CONTEXT("Internal rotation") { + auto disc = makeDisc(base, 30_mm, 100_mm, 10_degree, a(40_degree)); + auto disc2 = makeDisc(base, 30_mm, 100_mm, 45_degree, a(95_degree)); + + auto [disc3, reversed] = + disc->mergedWith(*disc2, Acts::BinningValue::binPhi, false, *logger); + BOOST_REQUIRE_NE(disc3, nullptr); + BOOST_CHECK_EQUAL(base.matrix(), disc3->transform(tgContext).matrix()); + BOOST_CHECK(reversed); + + auto [disc3Reversed, reversed2] = + disc2->mergedWith(*disc, Acts::BinningValue::binPhi, false, *logger); + BOOST_REQUIRE_NE(disc3Reversed, nullptr); + BOOST_CHECK(*disc3 == *disc3Reversed); + BOOST_CHECK(!reversed2); + + const auto* bounds = dynamic_cast(&disc3->bounds()); + BOOST_REQUIRE_NE(bounds, nullptr); + + BOOST_CHECK_SMALL( + detail::difference_periodic(bounds->get(RadialBounds::eAveragePhi), + a(85_degree), 2 * M_PI), + 1e-6); + BOOST_CHECK_CLOSE(bounds->get(RadialBounds::eHalfPhiSector), 55_degree, + 1e-6); + + auto disc4 = makeDisc(base, 30_mm, 100_mm, 20_degree, a(170_degree)); + auto disc5 = makeDisc(base, 30_mm, 100_mm, 10_degree, a(-160_degree)); + auto [disc45, reversed45] = + disc4->mergedWith(*disc5, Acts::BinningValue::binPhi, false, *logger); + BOOST_REQUIRE_NE(disc45, nullptr); + BOOST_CHECK_EQUAL(base.matrix(), disc45->transform(tgContext).matrix()); + BOOST_CHECK(reversed45); + + auto [disc54, reversed54] = + disc5->mergedWith(*disc4, Acts::BinningValue::binPhi, false, *logger); + BOOST_REQUIRE_NE(disc54, nullptr); + BOOST_CHECK(!reversed54); + + BOOST_CHECK(*disc54 == *disc45); + + const auto* bounds45 = dynamic_cast(&disc45->bounds()); + BOOST_REQUIRE_NE(bounds, nullptr); + + BOOST_CHECK_SMALL( + detail::difference_periodic(bounds45->get(RadialBounds::eAveragePhi), + a(180_degree), 2 * M_PI), + 1e-6); + BOOST_CHECK_CLOSE(bounds45->get(RadialBounds::eHalfPhiSector), 30_degree, + 1e-6); + + auto disc6 = makeDisc(base, 30_mm, 100_mm, 90_degree, a(0_degree)); + auto disc7 = makeDisc(base, 30_mm, 100_mm, 90_degree, a(180_degree)); + + auto [disc67, reversed67] = + disc6->mergedWith(*disc7, Acts::BinningValue::binPhi, false, *logger); + BOOST_REQUIRE_NE(disc67, nullptr); + CHECK_CLOSE_OR_SMALL(disc67->transform(tgContext).matrix(), base.matrix(), + 1e-6, 1e-10); + BOOST_CHECK(!reversed67); + + auto [disc76, reversed76] = + disc7->mergedWith(*disc6, Acts::BinningValue::binPhi, false, *logger); + BOOST_REQUIRE_NE(disc76, nullptr); + // surfaces are not equal because bounds are not equal + BOOST_CHECK(*disc76 != *disc67); + // bounds are different because of avg phi + BOOST_CHECK_NE(disc76->bounds(), disc67->bounds()); + // transforms should be the same + BOOST_CHECK_EQUAL(disc76->transform(tgContext).matrix(), + disc67->transform(tgContext).matrix()); + // not reversed either because you get the ordering you put in + BOOST_CHECK(!reversed76); + + const auto* bounds67 = dynamic_cast(&disc67->bounds()); + BOOST_REQUIRE_NE(bounds67, nullptr); + BOOST_CHECK_SMALL( + detail::difference_periodic(bounds67->get(RadialBounds::eAveragePhi), + a(90_degree), 2 * M_PI), + 1e-6); + BOOST_CHECK_CLOSE(bounds67->get(RadialBounds::eHalfPhiSector), 180_degree, + 1e-6); + } - BOOST_CHECK_SMALL( - detail::difference_periodic(bounds45->get(RadialBounds::eAveragePhi), - a(180_degree), 2 * M_PI), - 1e-6); - BOOST_CHECK_CLOSE(bounds45->get(RadialBounds::eHalfPhiSector), 30_degree, - 0.1); + BOOST_TEST_CONTEXT("External rotation") { + Transform3 trf1 = base * AngleAxis3(a(40_degree), Vector3::UnitZ()); + auto disc = makeDisc(trf1, 30_mm, 100_mm, 10_degree, 0_degree); + Transform3 trf2 = base * AngleAxis3(a(95_degree), Vector3::UnitZ()); + auto disc2 = makeDisc(trf2, 30_mm, 100_mm, 45_degree, 0_degree); + + auto [disc3, reversed] = + disc->mergedWith(*disc2, Acts::BinningValue::binPhi, true, *logger); + BOOST_REQUIRE_NE(disc3, nullptr); + Transform3 trfExpected12 = + base * AngleAxis3(a(85_degree), Vector3::UnitZ()); + CHECK_CLOSE_OR_SMALL(disc3->transform(tgContext).matrix(), + trfExpected12.matrix(), 1e-6, 1e-10); + BOOST_CHECK(reversed); + + auto [disc3Reversed, reversed2] = + disc2->mergedWith(*disc, Acts::BinningValue::binPhi, true, *logger); + BOOST_REQUIRE_NE(disc3Reversed, nullptr); + BOOST_CHECK(*disc3 == *disc3Reversed); + BOOST_CHECK(!reversed2); + + const auto* bounds = dynamic_cast(&disc3->bounds()); + BOOST_REQUIRE_NE(bounds, nullptr); + + BOOST_CHECK_EQUAL(bounds->get(RadialBounds::eAveragePhi), 0); + BOOST_CHECK_CLOSE(bounds->get(RadialBounds::eHalfPhiSector), 55_degree, + 1e-6); + + Transform3 trf4 = base * AngleAxis3(a(170_degree), Vector3::UnitZ()); + auto disc4 = makeDisc(trf4, 30_mm, 100_mm, 20_degree, 0_degree); + Transform3 trf5 = base * AngleAxis3(a(-160_degree), Vector3::UnitZ()); + auto disc5 = makeDisc(trf5, 30_mm, 100_mm, 10_degree, 0_degree); + auto [disc45, reversed45] = + disc4->mergedWith(*disc5, Acts::BinningValue::binPhi, true, *logger); + BOOST_REQUIRE_NE(disc45, nullptr); + Transform3 trfExpected45 = + base * AngleAxis3(a(180_degree), Vector3::UnitZ()); + CHECK_CLOSE_OR_SMALL(disc45->transform(tgContext).matrix(), + trfExpected45.matrix(), 1e-6, 1e-10); + BOOST_CHECK(reversed45); + + auto [disc54, reversed54] = + disc5->mergedWith(*disc4, Acts::BinningValue::binPhi, true, *logger); + BOOST_REQUIRE_NE(disc54, nullptr); + BOOST_CHECK(!reversed54); + + BOOST_CHECK(*disc54 == *disc45); + + const auto* bounds45 = dynamic_cast(&disc45->bounds()); + BOOST_REQUIRE_NE(bounds, nullptr); + + BOOST_CHECK_EQUAL(bounds45->get(RadialBounds::eAveragePhi), 0); + BOOST_CHECK_CLOSE(bounds45->get(RadialBounds::eHalfPhiSector), 30_degree, + 1e-6); + + Transform3 trf6 = base * AngleAxis3(a(0_degree), Vector3::UnitZ()); + auto disc6 = makeDisc(trf6, 30_mm, 100_mm, 90_degree, 0_degree); + Transform3 trf7 = base * AngleAxis3(a(180_degree), Vector3::UnitZ()); + auto disc7 = makeDisc(trf7, 30_mm, 100_mm, 90_degree, 0_degree); + auto [disc67, reversed67] = + disc6->mergedWith(*disc7, Acts::BinningValue::binPhi, true, *logger); + BOOST_REQUIRE_NE(disc67, nullptr); + Transform3 trfExpected67 = + base * AngleAxis3(a(90_degree), Vector3::UnitZ()); + CHECK_CLOSE_OR_SMALL(disc67->transform(tgContext).matrix(), + trfExpected67.matrix(), 1e-6, 1e-10); + BOOST_CHECK(!reversed67); + + auto [disc76, reversed76] = + disc7->mergedWith(*disc6, Acts::BinningValue::binPhi, true, *logger); + BOOST_REQUIRE_NE(disc76, nullptr); + // surfaces are not equal due to different transforms + BOOST_CHECK(*disc76 != *disc67); + BOOST_CHECK_NE(disc76->transform(tgContext).matrix(), + disc67->transform(tgContext).matrix()); + // bounds should be equal however + BOOST_CHECK_EQUAL(disc76->bounds(), disc67->bounds()); + + BOOST_CHECK(!reversed76); // not reversed either because you get the + // ordering you put in + + const auto* bounds67 = dynamic_cast(&disc67->bounds()); + BOOST_REQUIRE_NE(bounds67, nullptr); + BOOST_CHECK_EQUAL(bounds67->get(RadialBounds::eAveragePhi), 0); + BOOST_CHECK_CLOSE(bounds67->get(RadialBounds::eHalfPhiSector), 180_degree, + 1e-6); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/Tests/UnitTests/Core/Utilities/AxesTests.cpp b/Tests/UnitTests/Core/Utilities/AxesTests.cpp index 77d57d8961e..b155bec7a43 100644 --- a/Tests/UnitTests/Core/Utilities/AxesTests.cpp +++ b/Tests/UnitTests/Core/Utilities/AxesTests.cpp @@ -16,6 +16,7 @@ #include namespace Acts::Test { +BOOST_AUTO_TEST_SUITE(Axes) BOOST_AUTO_TEST_CASE(equidistant_axis) { Axis a(0.0, 10.0, 10u); @@ -398,4 +399,90 @@ BOOST_AUTO_TEST_CASE(AxisTypeDeduction) { Axis>); } +BOOST_AUTO_TEST_CASE(AxisVisit) { + using enum AxisBoundaryType; + using enum AxisType; + + auto eqOpen = Axis{0.0, 10., 10}; + eqOpen.visit([](const auto& axis) { + BOOST_CHECK(( + std::is_same_v, Axis>)); + }); + + auto eqBound = Axis{AxisBound, 0.0, 10., 10}; + eqBound.visit([](const auto& axis) { + BOOST_CHECK((std::is_same_v, + Axis>)); + }); + + auto eqClosed = Axis{AxisClosed, 0.0, 10., 10}; + eqClosed.visit([](const auto& axis) { + BOOST_CHECK((std::is_same_v, + Axis>)); + }); + + auto varOpen = Axis{{0, 1, 2., 3, 4}}; + varOpen.visit([](const auto& axis) { + BOOST_CHECK( + (std::is_same_v, Axis>)); + }); + + auto varBound = Axis{AxisBound, {0, 1, 2., 3, 4}}; + varBound.visit([](const auto& axis) { + BOOST_CHECK( + (std::is_same_v, Axis>)); + }); + + auto varClosed = Axis{AxisClosed, {0, 1, 2., 3, 4}}; + varClosed.visit([](const auto& axis) { + BOOST_CHECK( + (std::is_same_v, Axis>)); + }); +} + +BOOST_AUTO_TEST_CASE(Output) { + std::stringstream ss; + + Axis a{AxisBound, 0.0, 10., 10}; + Axis b{AxisBound, {0.0, 10., 11}}; + + ss << a; + + BOOST_CHECK_EQUAL(ss.str(), "Axis(0, 10, 10)"); + + ss.str(""); + + const IAxis& ia = a; + + ss << ia; + + BOOST_CHECK_EQUAL(ss.str(), "Axis(0, 10, 10)"); + + ss.str(""); + + ss << b; + + BOOST_CHECK_EQUAL(ss.str(), "Axis(0, 10, 11)"); +} + +BOOST_AUTO_TEST_CASE(Equality) { + Axis a{AxisBound, 0.0, 10., 10}; + Axis b{AxisClosed, 0.0, 10., 10}; + + BOOST_CHECK_EQUAL(a, a); + BOOST_CHECK_NE(a, b); + + const IAxis& ia = a; + const IAxis& ib = b; + + BOOST_CHECK_EQUAL(ia, ia); + BOOST_CHECK_NE(ia, ib); + BOOST_CHECK_NE(ia, b); + BOOST_CHECK_NE(a, ib); + BOOST_CHECK_EQUAL(a, ia); + BOOST_CHECK_EQUAL(b, ib); +} + +BOOST_AUTO_TEST_SUITE_END() + } // namespace Acts::Test diff --git a/Tests/UnitTests/Core/Utilities/GridTests.cpp b/Tests/UnitTests/Core/Utilities/GridTests.cpp index 4aee40ce396..60defa3fde3 100644 --- a/Tests/UnitTests/Core/Utilities/GridTests.cpp +++ b/Tests/UnitTests/Core/Utilities/GridTests.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,8 @@ using namespace Acts::detail; namespace Acts::Test { +BOOST_AUTO_TEST_SUITE(GridTests) + BOOST_AUTO_TEST_CASE(grid_test_1d_equidistant) { using Point = std::array; using indices = std::array; @@ -1335,4 +1338,49 @@ BOOST_AUTO_TEST_CASE(grid_full_conversion) { BOOST_CHECK_EQUAL(g1ConvertedInt.atPosition(Point({{0.3}})), 1); BOOST_CHECK_EQUAL(g1ConvertedInt.atPosition(Point({{0.6}})), 2); } + +BOOST_AUTO_TEST_CASE(Output) { + Axis a{AxisOpen, 0.0, 1.0, 10u}; + Axis b{AxisBound, {1, 2, 3}}; + + Grid g(Type, std::move(a), std::move(b)); + + std::stringstream ss; + ss << g; + BOOST_CHECK_EQUAL( + ss.str(), + "Axis(0, 1, 10), Axis(1, 2, 3)"); + + const IGrid& ig = g; + + ss.str(""); + + ss << ig; + + BOOST_CHECK_EQUAL( + ss.str(), + "Axis(0, 1, 10), Axis(1, 2, 3)"); +} + +BOOST_AUTO_TEST_CASE(Equality) { + Axis a{AxisOpen, 0.0, 1.0, 10u}; + Axis b{AxisBound, {1, 2, 3}}; + Axis c{AxisClosed, {1, 2, 5}}; + + Grid ab{Type, a, b}; + Grid ac{Type, a, c}; + + BOOST_CHECK_EQUAL(ab, ab); + BOOST_CHECK_EQUAL(ac, ac); + BOOST_CHECK_NE(ab, ac); + + const IGrid& iab = ab; + const IGrid& iac = ac; + + BOOST_CHECK_EQUAL(iab, iab); + BOOST_CHECK_EQUAL(iac, iac); +} + +BOOST_AUTO_TEST_SUITE_END() + } // namespace Acts::Test diff --git a/cmake/ActsExternSources.cmake b/cmake/ActsExternSources.cmake index f58a901a1c5..4e5fc927cb1 100644 --- a/cmake/ActsExternSources.cmake +++ b/cmake/ActsExternSources.cmake @@ -22,10 +22,6 @@ set( ACTS_TRACCC_SOURCE "URL;https://github.com/acts-project/traccc/archive/refs/tags/v0.13.0.tar.gz;URL_MD5;1ddf757ddcbaa08fd7db3a7752ef7f98" CACHE STRING "Source to take TRACCC from") mark_as_advanced( ACTS_TRACCC_SOURCE ) -set( ACTS_DFELIBS_SOURCE - "URL;https://github.com/acts-project/dfelibs/archive/refs/tags/v20211029.tar.gz;URL_MD5;87fb09c5a11b98250f5e266e9cd501ea" CACHE STRING "Source to take dfelibs from") -mark_as_advanced( ACTS_DFELIBS_SOURCE ) - set( ACTS_FRNN_SOURCE "GIT_REPOSITORY;https://github.com/hrzhao76/FRNN/;GIT_TAG;5f8a48b0022300cd2863119f5646a5f31373e0c8" CACHE STRING "Source to take FRNN from") mark_as_advanced( ACTS_FRNN_SOURCE ) diff --git a/docs/getting_started.md b/docs/getting_started.md index 805ee54aa0f..29cc8bae650 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -285,7 +285,6 @@ components. | ACTS_USE_SYSTEM_COVFIE | Use a system-provided covfie
installation
type: `bool`, default: `ACTS_USE_SYSTEM_LIBS -> OFF` | | ACTS_USE_SYSTEM_DETRAY | Use a system-provided detray
installation
type: `bool`, default: `ACTS_USE_SYSTEM_LIBS -> OFF` | | ACTS_USE_SYSTEM_TRACCC | Use a system-provided traccc
installation
type: `bool`, default: `ACTS_USE_SYSTEM_LIBS -> OFF` | -| ACTS_USE_SYSTEM_DFELIBS | Use a system-provided dfelibs
installation
type: `bool`, default: `ACTS_USE_SYSTEM_LIBS -> OFF` | | ACTS_USE_SYSTEM_VECMEM | Use a system-provided vecmem
installation
type: `bool`, default: `ACTS_USE_SYSTEM_LIBS -> OFF` | | ACTS_USE_SYSTEM_ALGEBRAPLUGINS | Use a system-provided algebra-plugins
installation
type: `bool`, default: `ACTS_USE_SYSTEM_LIBS -> OFF` | | ACTS_BUILD_PLUGIN_TGEO | Build TGeo plugin
type: `bool`, default: `OFF` | diff --git a/thirdparty/README.md b/thirdparty/README.md index ca89ca9e040..c4eeda8a48a 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -10,10 +10,6 @@ issues with missing files after installation. `nlohmann_json` is exempted from this rule as it is handled specially. -## dfelibs - -CMake instructions to build [dfelibs](https://github.com/msmk0/dfelibs). - ## nlohmann_json CMake instructions to build [nlohmann::json](https://github.com/nlohmann/json). diff --git a/thirdparty/dfelibs/CMakeLists.txt b/thirdparty/dfelibs/CMakeLists.txt deleted file mode 100644 index c3dc15c53d0..00000000000 --- a/thirdparty/dfelibs/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -include( FetchContent ) - -# Tell the user what's happening. -message( STATUS "Building dfelibs as part of the ACTS project" ) - -set( DFELIBS_VERSION "v${_acts_dfelibs_version}") - -# Declare where to get dfelibs from. -FetchContent_Declare( dfelibs ${ACTS_DFELIBS_SOURCE} ) - -# Options used in the build of dfelibs. -set( dfelibs_BUILD_EXAMPLES OFF CACHE BOOL - "Turn off the build of the dfelibs examples" ) -set( dfelibs_BUILD_UNITTESTS OFF CACHE BOOL - "Turn off the build of the dfelibs unit tests" ) -set( dfelibs_ENABLE_INSTALL ON CACHE BOOL - "Have dfelibs be installed together with the rest of the project" ) - -# Now set up its build. -FetchContent_MakeAvailable( dfelibs ) diff --git a/thirdparty/dfelibs/README.md b/thirdparty/dfelibs/README.md deleted file mode 100644 index 4b2960be096..00000000000 --- a/thirdparty/dfelibs/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Build Recipe for dfelibs - -This directory holds a simple build recipe for the -[dfelibs](https://github.com/acts-project/dfelibs) project. diff --git a/thirdparty/traccc/CMakeLists.txt b/thirdparty/traccc/CMakeLists.txt index 73597b29f36..cd7307f38f4 100644 --- a/thirdparty/traccc/CMakeLists.txt +++ b/thirdparty/traccc/CMakeLists.txt @@ -30,8 +30,8 @@ set( TRACCC_SETUP_COVFIE OFF CACHE BOOL "Do not set up Covfie as part of Traccc" ) set( TRACCC_SETUP_DFELIBS OFF CACHE BOOL "Do not set up dfelibs as part of Traccc" ) -set( TRACCC_SETUP_DETRAY OFF CACHE BOOL - "Do not set up Detray as part of Traccc" ) +set( TRACCC_SETUP_DETRAY ON CACHE BOOL + "Set up Detray as part of Traccc" ) set( TRACCC_SETUP_ACTS OFF CACHE BOOL "Do not set up ACTS as part of Traccc" ) set( TRACCC_SETUP_TBB OFF CACHE BOOL