From 6f8887c17a0dc0d5265382645d067342c8690d52 Mon Sep 17 00:00:00 2001 From: James Shen Date: Fri, 18 Jul 2025 16:52:36 -0400 Subject: [PATCH 1/7] Move triggeralgs to a dedicated directory for dunedaqv4 --- dunetrigger/CMakeLists.txt | 1 - dunetrigger/TriggerSim/CMakeLists.txt | 1 + dunetrigger/TriggerSim/triggeralgs/CMakeLists.txt | 1 + .../v4}/.github/workflows/auto_approve.yml | 0 .../v4}/.github/workflows/dunedaq-v4-cpp-ci.yml | 0 .../v4}/.github/workflows/track_new_issues.yml | 0 .../v4}/.github/workflows/track_new_prs.yml | 0 .../triggeralgs/v4}/.gitignore | 0 .../triggeralgs/v4}/CMakeLists.txt | 0 .../triggeralgs/v4}/README-DUNEDAQ.md | 0 .../triggeralgs/v4}/README.md | 0 .../triggeralgs/v4}/include/CMakeLists.txt | 0 .../ADCSimpleWindow/AlgorithmFlowChart.png | Bin .../include/triggeralgs/ADCSimpleWindow/README.md | 0 .../TriggerActivityMakerADCSimpleWindow.hpp | 4 ++-- .../TriggerCandidateMakerADCSimpleWindow.hpp | 2 +- .../v4}/include/triggeralgs/AbstractFactory.hpp | 2 +- .../v4}/include/triggeralgs/AbstractFactory.hxx | 2 +- .../BundleN/TriggerActivityMakerBundleN.hpp | 2 +- .../BundleN/TriggerCandidateMakerBundleN.hpp | 2 +- .../include/triggeralgs/ChannelAdjacency/README.md | 0 .../TriggerActivityMakerChannelAdjacency.hpp | 4 ++-- .../TriggerCandidateMakerChannelAdjacency.hpp | 4 ++-- .../TriggerActivityMakerChannelDistance.hpp | 2 +- .../TriggerCandidateMakerChannelDistance.hpp | 2 +- .../include/triggeralgs/HorizontalMuon/README.md | 0 .../TriggerActivityMakerHorizontalMuon.hpp | 4 ++-- .../TriggerCandidateMakerHorizontalMuon.hpp | 4 ++-- .../triggeralgs/v4}/include/triggeralgs/Issues.hpp | 0 .../triggeralgs/v4}/include/triggeralgs/Logging.hpp | 0 .../include/triggeralgs/MichelElectron/README.md | 0 .../TriggerActivityMakerMichelElectron.hpp | 2 +- .../TriggerCandidateMakerMichelElectron.hpp | 4 ++-- .../include/triggeralgs/PlaneCoincidence/README.md | 0 .../TriggerActivityMakerPlaneCoincidence.hpp | 4 ++-- .../TriggerCandidateMakerPlaneCoincidence.hpp | 4 ++-- .../Prescale/TriggerActivityMakerPrescale.hpp | 2 +- .../Prescale/TriggerCandidateMakerPrescale.hpp | 2 +- .../Supernova/TriggerActivityMakerSupernova.hpp | 2 +- .../Supernova/TriggerCandidateMakerSupernova.hpp | 4 ++-- .../Supernova/TriggerDecisionMakerSupernova.hpp | 2 +- .../v4}/include/triggeralgs/TAWindow.hpp | 4 ++-- .../v4}/include/triggeralgs/TPWindow.hpp | 4 ++-- .../v4}/include/triggeralgs/TriggerActivity.hpp | 2 +- .../include/triggeralgs/TriggerActivityFactory.hpp | 4 ++-- .../include/triggeralgs/TriggerActivityMaker.hpp | 10 +++++----- .../v4}/include/triggeralgs/TriggerCandidate.hpp | 0 .../include/triggeralgs/TriggerCandidateFactory.hpp | 4 ++-- .../include/triggeralgs/TriggerCandidateMaker.hpp | 10 +++++----- .../v4}/include/triggeralgs/TriggerDecision.hpp | 4 ++-- .../include/triggeralgs/TriggerDecisionMaker.hpp | 8 ++++---- .../include/triggeralgs/TriggerObjectOverlay.hpp | 6 +++--- .../v4}/include/triggeralgs/TriggerPrimitive.hpp | 0 .../include/triggeralgs/TriggerPrimitiveMaker.hpp | 4 ++-- .../triggeralgs/v4}/include/triggeralgs/Types.hpp | 0 .../v4}/include/triggeralgs/dbscan/Hit.hpp | 4 ++-- .../dbscan/TriggerActivityMakerDBSCAN.hpp | 4 ++-- .../dbscan/TriggerCandidateMakerDBSCAN.hpp | 4 ++-- .../v4}/include/triggeralgs/dbscan/dbscan.hpp | 4 ++-- .../triggeralgs/v4}/src/TAWindow.cpp | 2 +- .../triggeralgs/v4}/src/TPWindow.cpp | 2 +- .../v4}/src/TriggerActivityMakerADCSimpleWindow.cpp | 2 +- .../v4}/src/TriggerActivityMakerBundleN.cpp | 2 +- .../src/TriggerActivityMakerChannelAdjacency.cpp | 4 ++-- .../v4}/src/TriggerActivityMakerChannelDistance.cpp | 2 +- .../v4}/src/TriggerActivityMakerDBSCAN.cpp | 4 ++-- .../v4}/src/TriggerActivityMakerHorizontalMuon.cpp | 2 +- .../v4}/src/TriggerActivityMakerMichelElectron.cpp | 2 +- .../src/TriggerActivityMakerPlaneCoincidence.cpp | 2 +- .../v4}/src/TriggerActivityMakerPrescale.cpp | 2 +- .../v4}/src/TriggerActivityMakerSupernova.cpp | 2 +- .../src/TriggerCandidateMakerADCSimpleWindow.cpp | 2 +- .../v4}/src/TriggerCandidateMakerBundleN.cpp | 2 +- .../src/TriggerCandidateMakerChannelAdjacency.cpp | 4 ++-- .../src/TriggerCandidateMakerChannelDistance.cpp | 2 +- .../v4}/src/TriggerCandidateMakerDBSCAN.cpp | 2 +- .../v4}/src/TriggerCandidateMakerHorizontalMuon.cpp | 2 +- .../v4}/src/TriggerCandidateMakerMichelElectron.cpp | 2 +- .../src/TriggerCandidateMakerPlaneCoincidence.cpp | 2 +- .../v4}/src/TriggerCandidateMakerPrescale.cpp | 2 +- .../v4}/src/TriggerCandidateMakerSupernova.cpp | 2 +- .../v4}/src/TriggerDecisionMakerSupernova.cpp | 2 +- .../triggeralgs/v4}/src/dbscan/Hit.cpp | 2 +- .../triggeralgs/v4}/src/dbscan/Point.hpp | 0 .../triggeralgs/v4}/src/dbscan/dbscan.cpp | 4 ++-- 85 files changed, 99 insertions(+), 98 deletions(-) create mode 100644 dunetrigger/TriggerSim/triggeralgs/CMakeLists.txt rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/.github/workflows/auto_approve.yml (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/.github/workflows/dunedaq-v4-cpp-ci.yml (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/.github/workflows/track_new_issues.yml (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/.github/workflows/track_new_prs.yml (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/.gitignore (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/CMakeLists.txt (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/README-DUNEDAQ.md (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/README.md (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/CMakeLists.txt (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/ADCSimpleWindow/AlgorithmFlowChart.png (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/ADCSimpleWindow/README.md (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/ADCSimpleWindow/TriggerActivityMakerADCSimpleWindow.hpp (94%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/ADCSimpleWindow/TriggerCandidateMakerADCSimpleWindow.hpp (91%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/AbstractFactory.hpp (93%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/AbstractFactory.hxx (95%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/BundleN/TriggerActivityMakerBundleN.hpp (89%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/BundleN/TriggerCandidateMakerBundleN.hpp (89%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/ChannelAdjacency/README.md (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/ChannelAdjacency/TriggerActivityMakerChannelAdjacency.hpp (90%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/ChannelAdjacency/TriggerCandidateMakerChannelAdjacency.hpp (89%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/ChannelDistance/TriggerActivityMakerChannelDistance.hpp (92%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/ChannelDistance/TriggerCandidateMakerChannelDistance.hpp (91%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/HorizontalMuon/README.md (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/HorizontalMuon/TriggerActivityMakerHorizontalMuon.hpp (93%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/HorizontalMuon/TriggerCandidateMakerHorizontalMuon.hpp (89%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/Issues.hpp (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/Logging.hpp (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/MichelElectron/README.md (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/MichelElectron/TriggerActivityMakerMichelElectron.hpp (98%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/MichelElectron/TriggerCandidateMakerMichelElectron.hpp (96%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/PlaneCoincidence/README.md (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/PlaneCoincidence/TriggerActivityMakerPlaneCoincidence.hpp (94%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/PlaneCoincidence/TriggerCandidateMakerPlaneCoincidence.hpp (89%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/Prescale/TriggerActivityMakerPrescale.hpp (89%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/Prescale/TriggerCandidateMakerPrescale.hpp (91%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/Supernova/TriggerActivityMakerSupernova.hpp (97%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/Supernova/TriggerCandidateMakerSupernova.hpp (91%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/Supernova/TriggerDecisionMakerSupernova.hpp (95%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TAWindow.hpp (91%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TPWindow.hpp (84%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerActivity.hpp (87%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerActivityFactory.hpp (87%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerActivityMaker.hpp (67%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerCandidate.hpp (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerCandidateFactory.hpp (87%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerCandidateMaker.hpp (68%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerDecision.hpp (85%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerDecisionMaker.hpp (71%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerObjectOverlay.hpp (94%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerPrimitive.hpp (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/TriggerPrimitiveMaker.hpp (85%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/Types.hpp (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/dbscan/Hit.hpp (95%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/dbscan/TriggerActivityMakerDBSCAN.hpp (84%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/dbscan/TriggerCandidateMakerDBSCAN.hpp (84%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/include/triggeralgs/dbscan/dbscan.hpp (95%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TAWindow.cpp (97%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TPWindow.cpp (97%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerActivityMakerADCSimpleWindow.cpp (97%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerActivityMakerBundleN.cpp (96%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerActivityMakerChannelAdjacency.cpp (97%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerActivityMakerChannelDistance.cpp (96%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerActivityMakerDBSCAN.cpp (92%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerActivityMakerHorizontalMuon.cpp (99%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerActivityMakerMichelElectron.cpp (99%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerActivityMakerPlaneCoincidence.cpp (98%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerActivityMakerPrescale.cpp (94%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerActivityMakerSupernova.cpp (95%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerCandidateMakerADCSimpleWindow.cpp (94%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerCandidateMakerBundleN.cpp (95%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerCandidateMakerChannelAdjacency.cpp (96%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerCandidateMakerChannelDistance.cpp (94%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerCandidateMakerDBSCAN.cpp (94%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerCandidateMakerHorizontalMuon.cpp (98%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerCandidateMakerMichelElectron.cpp (98%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerCandidateMakerPlaneCoincidence.cpp (98%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerCandidateMakerPrescale.cpp (94%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerCandidateMakerSupernova.cpp (93%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/TriggerDecisionMakerSupernova.cpp (91%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/dbscan/Hit.cpp (96%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/dbscan/Point.hpp (100%) rename dunetrigger/{triggeralgs => TriggerSim/triggeralgs/v4}/src/dbscan/dbscan.cpp (98%) diff --git a/dunetrigger/CMakeLists.txt b/dunetrigger/CMakeLists.txt index 87e87d6..7026944 100644 --- a/dunetrigger/CMakeLists.txt +++ b/dunetrigger/CMakeLists.txt @@ -1,7 +1,6 @@ # basic source code CMakeLists.txt add_subdirectory(channelmaps) -add_subdirectory(triggeralgs) add_subdirectory(TriggerSim) add_subdirectory(TriggerAna) diff --git a/dunetrigger/TriggerSim/CMakeLists.txt b/dunetrigger/TriggerSim/CMakeLists.txt index 4dc1b3f..e507a68 100644 --- a/dunetrigger/TriggerSim/CMakeLists.txt +++ b/dunetrigger/TriggerSim/CMakeLists.txt @@ -1,5 +1,6 @@ include_directories("${dunedetdataformats_DIR}/../../../include") # there's a neater way? +add_subdirectory(triggeralgs) add_subdirectory(TPAlgTools) add_subdirectory(fcl) diff --git a/dunetrigger/TriggerSim/triggeralgs/CMakeLists.txt b/dunetrigger/TriggerSim/triggeralgs/CMakeLists.txt new file mode 100644 index 0000000..194866c --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(v4) diff --git a/dunetrigger/triggeralgs/.github/workflows/auto_approve.yml b/dunetrigger/TriggerSim/triggeralgs/v4/.github/workflows/auto_approve.yml similarity index 100% rename from dunetrigger/triggeralgs/.github/workflows/auto_approve.yml rename to dunetrigger/TriggerSim/triggeralgs/v4/.github/workflows/auto_approve.yml diff --git a/dunetrigger/triggeralgs/.github/workflows/dunedaq-v4-cpp-ci.yml b/dunetrigger/TriggerSim/triggeralgs/v4/.github/workflows/dunedaq-v4-cpp-ci.yml similarity index 100% rename from dunetrigger/triggeralgs/.github/workflows/dunedaq-v4-cpp-ci.yml rename to dunetrigger/TriggerSim/triggeralgs/v4/.github/workflows/dunedaq-v4-cpp-ci.yml diff --git a/dunetrigger/triggeralgs/.github/workflows/track_new_issues.yml b/dunetrigger/TriggerSim/triggeralgs/v4/.github/workflows/track_new_issues.yml similarity index 100% rename from dunetrigger/triggeralgs/.github/workflows/track_new_issues.yml rename to dunetrigger/TriggerSim/triggeralgs/v4/.github/workflows/track_new_issues.yml diff --git a/dunetrigger/triggeralgs/.github/workflows/track_new_prs.yml b/dunetrigger/TriggerSim/triggeralgs/v4/.github/workflows/track_new_prs.yml similarity index 100% rename from dunetrigger/triggeralgs/.github/workflows/track_new_prs.yml rename to dunetrigger/TriggerSim/triggeralgs/v4/.github/workflows/track_new_prs.yml diff --git a/dunetrigger/triggeralgs/.gitignore b/dunetrigger/TriggerSim/triggeralgs/v4/.gitignore similarity index 100% rename from dunetrigger/triggeralgs/.gitignore rename to dunetrigger/TriggerSim/triggeralgs/v4/.gitignore diff --git a/dunetrigger/triggeralgs/CMakeLists.txt b/dunetrigger/TriggerSim/triggeralgs/v4/CMakeLists.txt similarity index 100% rename from dunetrigger/triggeralgs/CMakeLists.txt rename to dunetrigger/TriggerSim/triggeralgs/v4/CMakeLists.txt diff --git a/dunetrigger/triggeralgs/README-DUNEDAQ.md b/dunetrigger/TriggerSim/triggeralgs/v4/README-DUNEDAQ.md similarity index 100% rename from dunetrigger/triggeralgs/README-DUNEDAQ.md rename to dunetrigger/TriggerSim/triggeralgs/v4/README-DUNEDAQ.md diff --git a/dunetrigger/triggeralgs/README.md b/dunetrigger/TriggerSim/triggeralgs/v4/README.md similarity index 100% rename from dunetrigger/triggeralgs/README.md rename to dunetrigger/TriggerSim/triggeralgs/v4/README.md diff --git a/dunetrigger/triggeralgs/include/CMakeLists.txt b/dunetrigger/TriggerSim/triggeralgs/v4/include/CMakeLists.txt similarity index 100% rename from dunetrigger/triggeralgs/include/CMakeLists.txt rename to dunetrigger/TriggerSim/triggeralgs/v4/include/CMakeLists.txt diff --git a/dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/AlgorithmFlowChart.png b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/AlgorithmFlowChart.png similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/AlgorithmFlowChart.png rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/AlgorithmFlowChart.png diff --git a/dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/README.md b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/README.md similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/README.md rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/README.md diff --git a/dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/TriggerActivityMakerADCSimpleWindow.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/TriggerActivityMakerADCSimpleWindow.hpp similarity index 94% rename from dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/TriggerActivityMakerADCSimpleWindow.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/TriggerActivityMakerADCSimpleWindow.hpp index 1908b68..24fbb2a 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/TriggerActivityMakerADCSimpleWindow.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/TriggerActivityMakerADCSimpleWindow.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_ADCSIMPLEWINDOW_TRIGGERACTIVITYMAKERADCSIMPLEWINDOW_HPP_ #define TRIGGERALGS_ADCSIMPLEWINDOW_TRIGGERACTIVITYMAKERADCSIMPLEWINDOW_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Types.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Types.hpp" #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/TriggerCandidateMakerADCSimpleWindow.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/TriggerCandidateMakerADCSimpleWindow.hpp similarity index 91% rename from dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/TriggerCandidateMakerADCSimpleWindow.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/TriggerCandidateMakerADCSimpleWindow.hpp index e9bc296..6df3cf5 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/TriggerCandidateMakerADCSimpleWindow.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/TriggerCandidateMakerADCSimpleWindow.hpp @@ -9,7 +9,7 @@ #ifndef TRIGGERALGS_ADCSIMPLEWINDOW_TRIGGERCANDIDATEMAKERADCSIMPLEWINDOW_HPP_ #define TRIGGERALGS_ADCSIMPLEWINDOW_TRIGGERCANDIDATEMAKERADCSIMPLEWINDOW_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/AbstractFactory.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/AbstractFactory.hpp similarity index 93% rename from dunetrigger/triggeralgs/include/triggeralgs/AbstractFactory.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/AbstractFactory.hpp index 712091e..59141a9 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/AbstractFactory.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/AbstractFactory.hpp @@ -44,6 +44,6 @@ class AbstractFactory } /* namespace triggeralgs */ -#include "dunetrigger/triggeralgs/include/triggeralgs/AbstractFactory.hxx" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/AbstractFactory.hxx" #endif // TRIGGERALGS_ABSTRACT_FACTORY_HPP_ diff --git a/dunetrigger/triggeralgs/include/triggeralgs/AbstractFactory.hxx b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/AbstractFactory.hxx similarity index 95% rename from dunetrigger/triggeralgs/include/triggeralgs/AbstractFactory.hxx rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/AbstractFactory.hxx index d98d04b..81fca40 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/AbstractFactory.hxx +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/AbstractFactory.hxx @@ -8,7 +8,7 @@ #ifndef TRIGGERALGS_ABSTRACT_FACTORY_HXX_ #define TRIGGERALGS_ABSTRACT_FACTORY_HXX_ -#include "dunetrigger/triggeralgs/include/triggeralgs/Issues.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Issues.hpp" namespace triggeralgs { diff --git a/dunetrigger/triggeralgs/include/triggeralgs/BundleN/TriggerActivityMakerBundleN.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/BundleN/TriggerActivityMakerBundleN.hpp similarity index 89% rename from dunetrigger/triggeralgs/include/triggeralgs/BundleN/TriggerActivityMakerBundleN.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/BundleN/TriggerActivityMakerBundleN.hpp index f6f1ed2..76aa25f 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/BundleN/TriggerActivityMakerBundleN.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/BundleN/TriggerActivityMakerBundleN.hpp @@ -9,7 +9,7 @@ #ifndef TRIGGERALGS_BUNDLEN_TRIGGERACTIVITYMAKERBUNDLEN_HPP_ #define TRIGGERALGS_BUNDLEN_TRIGGERACTIVITYMAKERBUNDLEN_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/BundleN/TriggerCandidateMakerBundleN.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/BundleN/TriggerCandidateMakerBundleN.hpp similarity index 89% rename from dunetrigger/triggeralgs/include/triggeralgs/BundleN/TriggerCandidateMakerBundleN.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/BundleN/TriggerCandidateMakerBundleN.hpp index 13c8ac9..668bcae 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/BundleN/TriggerCandidateMakerBundleN.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/BundleN/TriggerCandidateMakerBundleN.hpp @@ -9,7 +9,7 @@ #ifndef TRIGGERALGS_BUNDLEN_TRIGGERCANDIDATEMAKERBUNDLEN_HPP_ #define TRIGGERALGS_BUNDLEN_TRIGGERCANDIDATEMAKERBUNDLEN_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/ChannelAdjacency/README.md b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelAdjacency/README.md similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/ChannelAdjacency/README.md rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelAdjacency/README.md diff --git a/dunetrigger/triggeralgs/include/triggeralgs/ChannelAdjacency/TriggerActivityMakerChannelAdjacency.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelAdjacency/TriggerActivityMakerChannelAdjacency.hpp similarity index 90% rename from dunetrigger/triggeralgs/include/triggeralgs/ChannelAdjacency/TriggerActivityMakerChannelAdjacency.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelAdjacency/TriggerActivityMakerChannelAdjacency.hpp index 0ebc2b3..74067c8 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/ChannelAdjacency/TriggerActivityMakerChannelAdjacency.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelAdjacency/TriggerActivityMakerChannelAdjacency.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_CHANNELADJACENCY_TRIGGERACTIVITYMAKERCHANNELADJACENCY_HPP_ #define TRIGGERALGS_CHANNELADJACENCY_TRIGGERACTIVITYMAKERCHANNELADJACENCY_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TPWindow.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TPWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/ChannelAdjacency/TriggerCandidateMakerChannelAdjacency.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelAdjacency/TriggerCandidateMakerChannelAdjacency.hpp similarity index 89% rename from dunetrigger/triggeralgs/include/triggeralgs/ChannelAdjacency/TriggerCandidateMakerChannelAdjacency.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelAdjacency/TriggerCandidateMakerChannelAdjacency.hpp index fc121f4..674bee2 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/ChannelAdjacency/TriggerCandidateMakerChannelAdjacency.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelAdjacency/TriggerCandidateMakerChannelAdjacency.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_CHANNELADJACENCY_TRIGGERCANDIDATEMAKERCHANNELADJACENCY_HPP_ #define TRIGGERALGS_CHANNELADJACENCY_TRIGGERCANDIDATEMAKERCHANNELADJACENCY_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TAWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TAWindow.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/ChannelDistance/TriggerActivityMakerChannelDistance.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelDistance/TriggerActivityMakerChannelDistance.hpp similarity index 92% rename from dunetrigger/triggeralgs/include/triggeralgs/ChannelDistance/TriggerActivityMakerChannelDistance.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelDistance/TriggerActivityMakerChannelDistance.hpp index 4bc644a..a5ca147 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/ChannelDistance/TriggerActivityMakerChannelDistance.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelDistance/TriggerActivityMakerChannelDistance.hpp @@ -9,7 +9,7 @@ #ifndef TRIGGERALGS_CHANNELDISTANCE_TRIGGERACTIVITYMAKERCHANNELDISTANCE_HPP_ #define TRIGGERALGS_CHANNELDISTANCE_TRIGGERACTIVITYMAKERCHANNELDISTANCE_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" #include namespace triggeralgs { diff --git a/dunetrigger/triggeralgs/include/triggeralgs/ChannelDistance/TriggerCandidateMakerChannelDistance.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelDistance/TriggerCandidateMakerChannelDistance.hpp similarity index 91% rename from dunetrigger/triggeralgs/include/triggeralgs/ChannelDistance/TriggerCandidateMakerChannelDistance.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelDistance/TriggerCandidateMakerChannelDistance.hpp index 2c72c7d..6577a5b 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/ChannelDistance/TriggerCandidateMakerChannelDistance.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelDistance/TriggerCandidateMakerChannelDistance.hpp @@ -9,7 +9,7 @@ #ifndef TRIGGERALGS_CHANNELDISTANCE_TRIGGERCANDIDATEMAKERCHANNELDISTANCE_HPP_ #define TRIGGERALGS_CHANNELDISTANCE_TRIGGERCANDIDATEMAKERCHANNELDISTANCE_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" #include namespace triggeralgs { diff --git a/dunetrigger/triggeralgs/include/triggeralgs/HorizontalMuon/README.md b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/HorizontalMuon/README.md similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/HorizontalMuon/README.md rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/HorizontalMuon/README.md diff --git a/dunetrigger/triggeralgs/include/triggeralgs/HorizontalMuon/TriggerActivityMakerHorizontalMuon.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/HorizontalMuon/TriggerActivityMakerHorizontalMuon.hpp similarity index 93% rename from dunetrigger/triggeralgs/include/triggeralgs/HorizontalMuon/TriggerActivityMakerHorizontalMuon.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/HorizontalMuon/TriggerActivityMakerHorizontalMuon.hpp index 727639f..4483350 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/HorizontalMuon/TriggerActivityMakerHorizontalMuon.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/HorizontalMuon/TriggerActivityMakerHorizontalMuon.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_HORIZONTALMUON_TRIGGERACTIVITYMAKERHORIZONTALMUON_HPP_ #define TRIGGERALGS_HORIZONTALMUON_TRIGGERACTIVITYMAKERHORIZONTALMUON_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TPWindow.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TPWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/HorizontalMuon/TriggerCandidateMakerHorizontalMuon.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/HorizontalMuon/TriggerCandidateMakerHorizontalMuon.hpp similarity index 89% rename from dunetrigger/triggeralgs/include/triggeralgs/HorizontalMuon/TriggerCandidateMakerHorizontalMuon.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/HorizontalMuon/TriggerCandidateMakerHorizontalMuon.hpp index 1900e6c..bd416b6 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/HorizontalMuon/TriggerCandidateMakerHorizontalMuon.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/HorizontalMuon/TriggerCandidateMakerHorizontalMuon.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_HORIZONTALMUON_TRIGGERCANDIDATEMAKERHORIZONTALMUON_HPP_ #define TRIGGERALGS_HORIZONTALMUON_TRIGGERCANDIDATEMAKERHORIZONTALMUON_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TAWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TAWindow.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/Issues.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Issues.hpp similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/Issues.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Issues.hpp diff --git a/dunetrigger/triggeralgs/include/triggeralgs/Logging.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Logging.hpp similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/Logging.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Logging.hpp diff --git a/dunetrigger/triggeralgs/include/triggeralgs/MichelElectron/README.md b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/MichelElectron/README.md similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/MichelElectron/README.md rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/MichelElectron/README.md diff --git a/dunetrigger/triggeralgs/include/triggeralgs/MichelElectron/TriggerActivityMakerMichelElectron.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/MichelElectron/TriggerActivityMakerMichelElectron.hpp similarity index 98% rename from dunetrigger/triggeralgs/include/triggeralgs/MichelElectron/TriggerActivityMakerMichelElectron.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/MichelElectron/TriggerActivityMakerMichelElectron.hpp index 7c9917c..135a984 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/MichelElectron/TriggerActivityMakerMichelElectron.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/MichelElectron/TriggerActivityMakerMichelElectron.hpp @@ -9,7 +9,7 @@ #ifndef TRIGGERALGS_MICHELELECTRON_TRIGGERACTIVITYMAKERMICHELELECTRON_HPP_ #define TRIGGERALGS_MICHELELECTRON_TRIGGERACTIVITYMAKERMICHELELECTRON_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/MichelElectron/TriggerCandidateMakerMichelElectron.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/MichelElectron/TriggerCandidateMakerMichelElectron.hpp similarity index 96% rename from dunetrigger/triggeralgs/include/triggeralgs/MichelElectron/TriggerCandidateMakerMichelElectron.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/MichelElectron/TriggerCandidateMakerMichelElectron.hpp index 07c880b..f59cbb8 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/MichelElectron/TriggerCandidateMakerMichelElectron.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/MichelElectron/TriggerCandidateMakerMichelElectron.hpp @@ -9,9 +9,9 @@ #ifndef TRIGGERALGS_MICHELELECTRON_TRIGGERCANDIDATEMAKERMICHELELECTRON_HPP_ #define TRIGGERALGS_MICHELELECTRON_TRIGGERCANDIDATEMAKERMICHELELECTRON_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" -//#include "dunetrigger/triggeralgs/include/triggeralgs/triggercandidatemakerhorizontalmuon/Nljs.hpp" +//#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/triggercandidatemakerhorizontalmuon/Nljs.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/PlaneCoincidence/README.md b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/PlaneCoincidence/README.md similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/PlaneCoincidence/README.md rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/PlaneCoincidence/README.md diff --git a/dunetrigger/triggeralgs/include/triggeralgs/PlaneCoincidence/TriggerActivityMakerPlaneCoincidence.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/PlaneCoincidence/TriggerActivityMakerPlaneCoincidence.hpp similarity index 94% rename from dunetrigger/triggeralgs/include/triggeralgs/PlaneCoincidence/TriggerActivityMakerPlaneCoincidence.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/PlaneCoincidence/TriggerActivityMakerPlaneCoincidence.hpp index a996dda..9f7d218 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/PlaneCoincidence/TriggerActivityMakerPlaneCoincidence.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/PlaneCoincidence/TriggerActivityMakerPlaneCoincidence.hpp @@ -10,8 +10,8 @@ #define TRIGGERALGS_PLANECOINCIDENCE_TRIGGERACTIVITYMAKERPLANECOINCIDENCE_HPP_ #include "dunetrigger/channelmaps/OfflineTPCChannelMap.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TPWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TPWindow.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/PlaneCoincidence/TriggerCandidateMakerPlaneCoincidence.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/PlaneCoincidence/TriggerCandidateMakerPlaneCoincidence.hpp similarity index 89% rename from dunetrigger/triggeralgs/include/triggeralgs/PlaneCoincidence/TriggerCandidateMakerPlaneCoincidence.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/PlaneCoincidence/TriggerCandidateMakerPlaneCoincidence.hpp index cb42139..6bd9f8b 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/PlaneCoincidence/TriggerCandidateMakerPlaneCoincidence.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/PlaneCoincidence/TriggerCandidateMakerPlaneCoincidence.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_PLANECOINCIDENCE_TRIGGERCANDIDATEMAKERPLANECOINCIDENCE_HPP_ #define TRIGGERALGS_PLANECOINCIDENCE_TRIGGERCANDIDATEMAKERPLANECOINCIDENCE_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TAWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TAWindow.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/Prescale/TriggerActivityMakerPrescale.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Prescale/TriggerActivityMakerPrescale.hpp similarity index 89% rename from dunetrigger/triggeralgs/include/triggeralgs/Prescale/TriggerActivityMakerPrescale.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Prescale/TriggerActivityMakerPrescale.hpp index f41c3be..6532a6c 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/Prescale/TriggerActivityMakerPrescale.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Prescale/TriggerActivityMakerPrescale.hpp @@ -9,7 +9,7 @@ #ifndef TRIGGERALGS_PRESCALE_TRIGGERACTIVITYMAKERPRESCALE_HPP_ #define TRIGGERALGS_PRESCALE_TRIGGERACTIVITYMAKERPRESCALE_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/Prescale/TriggerCandidateMakerPrescale.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Prescale/TriggerCandidateMakerPrescale.hpp similarity index 91% rename from dunetrigger/triggeralgs/include/triggeralgs/Prescale/TriggerCandidateMakerPrescale.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Prescale/TriggerCandidateMakerPrescale.hpp index ad6f3f1..493b61e 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/Prescale/TriggerCandidateMakerPrescale.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Prescale/TriggerCandidateMakerPrescale.hpp @@ -9,7 +9,7 @@ #ifndef TRIGGERALGS_PRESCALE_TRIGGERCANDIDATEMAKERPRESCALE_HPP_ #define TRIGGERALGS_PRESCALE_TRIGGERCANDIDATEMAKERPRESCALE_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerActivityMakerSupernova.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerActivityMakerSupernova.hpp similarity index 97% rename from dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerActivityMakerSupernova.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerActivityMakerSupernova.hpp index 8ec877c..41d3eec 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerActivityMakerSupernova.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerActivityMakerSupernova.hpp @@ -9,7 +9,7 @@ #ifndef TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERACTIVITYMAKERSUPERNOVA_HPP_ #define TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERACTIVITYMAKERSUPERNOVA_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerCandidateMakerSupernova.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerCandidateMakerSupernova.hpp similarity index 91% rename from dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerCandidateMakerSupernova.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerCandidateMakerSupernova.hpp index 686e232..7134f3c 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerCandidateMakerSupernova.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerCandidateMakerSupernova.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERCANDIDATEMAKERSUPERNOVA_HPP_ #define TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERCANDIDATEMAKERSUPERNOVA_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Types.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Types.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerDecisionMakerSupernova.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerDecisionMakerSupernova.hpp similarity index 95% rename from dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerDecisionMakerSupernova.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerDecisionMakerSupernova.hpp index 983f601..36d42b1 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerDecisionMakerSupernova.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerDecisionMakerSupernova.hpp @@ -9,7 +9,7 @@ #ifndef TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERDECISIONMAKERSUPERNOVA_HPP_ #define TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERDECISIONMAKERSUPERNOVA_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerDecisionMaker.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerDecisionMaker.hpp" #include "detdataformats/trigger/Types.hpp" #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TAWindow.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TAWindow.hpp similarity index 91% rename from dunetrigger/triggeralgs/include/triggeralgs/TAWindow.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TAWindow.hpp index ae11b4f..7960083 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TAWindow.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TAWindow.hpp @@ -8,8 +8,8 @@ #ifndef TRIGGERALGS_TAWINDOW_HPP_ #define TRIGGERALGS_TAWINDOW_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivity.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Types.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Types.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TPWindow.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TPWindow.hpp similarity index 84% rename from dunetrigger/triggeralgs/include/triggeralgs/TPWindow.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TPWindow.hpp index 8e238a0..b745616 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TPWindow.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TPWindow.hpp @@ -8,8 +8,8 @@ #ifndef TRIGGERALGS_TPWINDOW_HPP_ #define TRIGGERALGS_TPWINDOW_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitive.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Types.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitive.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Types.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerActivity.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivity.hpp similarity index 87% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerActivity.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivity.hpp index c3d83c1..48de3eb 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TriggerActivity.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivity.hpp @@ -10,7 +10,7 @@ #define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERACTIVITY_HPP_ #include "detdataformats/trigger/TriggerActivityData.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitive.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitive.hpp" #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp similarity index 87% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp index b5868b1..29c4be9 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp @@ -8,8 +8,8 @@ #ifndef TRIGGERALGS_TRIGGER_ACTIVITY_FACTORY_HPP_ #define TRIGGERALGS_TRIGGER_ACTIVITY_FACTORY_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityMaker.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/AbstractFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityMaker.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/AbstractFactory.hpp" #define REGISTER_TRIGGER_ACTIVITY_MAKER(tam_name, tam_class) \ static struct tam_class##Registrar { \ diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityMaker.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityMaker.hpp similarity index 67% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityMaker.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityMaker.hpp index 8c2d3a5..53c8234 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityMaker.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityMaker.hpp @@ -9,11 +9,11 @@ #ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERACTIVITYMAKER_HPP_ #define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERACTIVITYMAKER_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/Issues.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Logging.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivity.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitive.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Types.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Issues.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Logging.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitive.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Types.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidate.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidate.hpp similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidate.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidate.hpp diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp similarity index 87% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp index b327c1f..7cd3206 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp @@ -8,8 +8,8 @@ #ifndef TRIGGERALGS_TRIGGER_CANDIDATE_FACTORY_HPP_ #define TRIGGERALGS_TRIGGER_CANDIDATE_FACTORY_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateMaker.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/AbstractFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateMaker.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/AbstractFactory.hpp" #define REGISTER_TRIGGER_CANDIDATE_MAKER(tcm_name, tcm_class) \ static struct tcm_class##Registrar { \ diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateMaker.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateMaker.hpp similarity index 68% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateMaker.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateMaker.hpp index 3795aa2..760406f 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateMaker.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateMaker.hpp @@ -9,11 +9,11 @@ #ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERCANDIDATEMAKER_HPP_ #define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERCANDIDATEMAKER_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/Issues.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Logging.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivity.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidate.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Types.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Issues.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Logging.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidate.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Types.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerDecision.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerDecision.hpp similarity index 85% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerDecision.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerDecision.hpp index 65b707d..0cc2cd0 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TriggerDecision.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerDecision.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERDECISION_HPP_ #define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERDECISION_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidate.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Types.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidate.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Types.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerDecisionMaker.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerDecisionMaker.hpp similarity index 71% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerDecisionMaker.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerDecisionMaker.hpp index 64564f8..e253cdc 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TriggerDecisionMaker.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerDecisionMaker.hpp @@ -9,10 +9,10 @@ #ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERDECISIONMAKER_HPP_ #define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERDECISIONMAKER_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/Issues.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Logging.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidate.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerDecision.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Issues.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Logging.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidate.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerDecision.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerObjectOverlay.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerObjectOverlay.hpp similarity index 94% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerObjectOverlay.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerObjectOverlay.hpp index 3a940d9..7b8a52c 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TriggerObjectOverlay.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerObjectOverlay.hpp @@ -13,9 +13,9 @@ #include "detdataformats/trigger/TriggerActivityData.hpp" #include "detdataformats/trigger/TriggerObjectOverlay.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitive.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivity.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidate.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitive.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidate.hpp" namespace triggeralgs { diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitive.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitive.hpp similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitive.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitive.hpp diff --git a/dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitiveMaker.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitiveMaker.hpp similarity index 85% rename from dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitiveMaker.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitiveMaker.hpp index 312c0fd..95a3c47 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitiveMaker.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitiveMaker.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERPRIMITIVEMAKER_HPP_ #define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERPRIMITIVEMAKER_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/Issues.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Logging.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Issues.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Logging.hpp" #include "detdataformats/trigger/TriggerPrimitive.hpp" #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/Types.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Types.hpp similarity index 100% rename from dunetrigger/triggeralgs/include/triggeralgs/Types.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Types.hpp diff --git a/dunetrigger/triggeralgs/include/triggeralgs/dbscan/Hit.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/Hit.hpp similarity index 95% rename from dunetrigger/triggeralgs/include/triggeralgs/dbscan/Hit.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/Hit.hpp index 4f2640e..5e4441c 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/dbscan/Hit.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/Hit.hpp @@ -1,7 +1,7 @@ #pragma once -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivity.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitive.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitive.hpp" #include #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/dbscan/TriggerActivityMakerDBSCAN.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/TriggerActivityMakerDBSCAN.hpp similarity index 84% rename from dunetrigger/triggeralgs/include/triggeralgs/dbscan/TriggerActivityMakerDBSCAN.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/TriggerActivityMakerDBSCAN.hpp index 3f8cb8a..b0e7a2b 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/dbscan/TriggerActivityMakerDBSCAN.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/TriggerActivityMakerDBSCAN.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_DBSCAN_TRIGGERACTIVITYMAKERDBSCAN_HPP_ #define TRIGGERALGS_DBSCAN_TRIGGERACTIVITYMAKERDBSCAN_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/dbscan/dbscan.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/dbscan.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/dbscan/TriggerCandidateMakerDBSCAN.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/TriggerCandidateMakerDBSCAN.hpp similarity index 84% rename from dunetrigger/triggeralgs/include/triggeralgs/dbscan/TriggerCandidateMakerDBSCAN.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/TriggerCandidateMakerDBSCAN.hpp index d625116..767b684 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/dbscan/TriggerCandidateMakerDBSCAN.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/TriggerCandidateMakerDBSCAN.hpp @@ -9,8 +9,8 @@ #ifndef TRIGGERALGS_DBSCAN_TRIGGERCANDIDATEMAKERDBSCAN_HPP_ #define TRIGGERALGS_DBSCAN_TRIGGERCANDIDATEMAKERDBSCAN_HPP_ -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/dbscan/dbscan.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/dbscan.hpp" #include #include diff --git a/dunetrigger/triggeralgs/include/triggeralgs/dbscan/dbscan.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/dbscan.hpp similarity index 95% rename from dunetrigger/triggeralgs/include/triggeralgs/dbscan/dbscan.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/dbscan.hpp index 0834afc..5e2fb36 100644 --- a/dunetrigger/triggeralgs/include/triggeralgs/dbscan/dbscan.hpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/dbscan.hpp @@ -7,8 +7,8 @@ #include #include -#include "dunetrigger/triggeralgs/include/triggeralgs/dbscan/Hit.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerPrimitive.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/Hit.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerPrimitive.hpp" namespace triggeralgs { namespace dbscan { diff --git a/dunetrigger/triggeralgs/src/TAWindow.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TAWindow.cpp similarity index 97% rename from dunetrigger/triggeralgs/src/TAWindow.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TAWindow.cpp index 3d2d59d..8bbb771 100644 --- a/dunetrigger/triggeralgs/src/TAWindow.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TAWindow.cpp @@ -1,4 +1,4 @@ -#include "dunetrigger/triggeralgs/include/triggeralgs/TAWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TAWindow.hpp" #include diff --git a/dunetrigger/triggeralgs/src/TPWindow.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TPWindow.cpp similarity index 97% rename from dunetrigger/triggeralgs/src/TPWindow.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TPWindow.cpp index 808de88..6e656fc 100644 --- a/dunetrigger/triggeralgs/src/TPWindow.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TPWindow.cpp @@ -1,5 +1,5 @@ -#include "dunetrigger/triggeralgs/include/triggeralgs/TPWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TPWindow.hpp" #include #include diff --git a/dunetrigger/triggeralgs/src/TriggerActivityMakerADCSimpleWindow.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerADCSimpleWindow.cpp similarity index 97% rename from dunetrigger/triggeralgs/src/TriggerActivityMakerADCSimpleWindow.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerADCSimpleWindow.cpp index 0626783..bea48c0 100644 --- a/dunetrigger/triggeralgs/src/TriggerActivityMakerADCSimpleWindow.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerADCSimpleWindow.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/TriggerActivityMakerADCSimpleWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/TriggerActivityMakerADCSimpleWindow.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerActivityMakerADCSimpleWindowPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerActivityMakerBundleN.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerBundleN.cpp similarity index 96% rename from dunetrigger/triggeralgs/src/TriggerActivityMakerBundleN.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerBundleN.cpp index 83fbce3..d6f6f6c 100644 --- a/dunetrigger/triggeralgs/src/TriggerActivityMakerBundleN.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerBundleN.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/BundleN/TriggerActivityMakerBundleN.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/BundleN/TriggerActivityMakerBundleN.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerActivityMakerBundleNPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerActivityMakerChannelAdjacency.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerChannelAdjacency.cpp similarity index 97% rename from dunetrigger/triggeralgs/src/TriggerActivityMakerChannelAdjacency.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerChannelAdjacency.cpp index ddf2217..6fd3097 100644 --- a/dunetrigger/triggeralgs/src/TriggerActivityMakerChannelAdjacency.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerChannelAdjacency.cpp @@ -6,9 +6,9 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/ChannelAdjacency/TriggerActivityMakerChannelAdjacency.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelAdjacency/TriggerActivityMakerChannelAdjacency.hpp" #include "TRACE/trace.h" -#include "dunetrigger/triggeralgs/include/triggeralgs/Logging.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Logging.hpp" #define TRACE_NAME "TriggerActivityMakerChannelAdjacencyPlugin" #include #include diff --git a/dunetrigger/triggeralgs/src/TriggerActivityMakerChannelDistance.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerChannelDistance.cpp similarity index 96% rename from dunetrigger/triggeralgs/src/TriggerActivityMakerChannelDistance.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerChannelDistance.cpp index 5ad9a18..a11ae47 100644 --- a/dunetrigger/triggeralgs/src/TriggerActivityMakerChannelDistance.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerChannelDistance.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/ChannelDistance/TriggerActivityMakerChannelDistance.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelDistance/TriggerActivityMakerChannelDistance.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerActivityMakerChannelDistancePlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerActivityMakerDBSCAN.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerDBSCAN.cpp similarity index 92% rename from dunetrigger/triggeralgs/src/TriggerActivityMakerDBSCAN.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerDBSCAN.cpp index 34ad2b7..fd17957 100644 --- a/dunetrigger/triggeralgs/src/TriggerActivityMakerDBSCAN.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerDBSCAN.cpp @@ -6,11 +6,11 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/dbscan/TriggerActivityMakerDBSCAN.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/TriggerActivityMakerDBSCAN.hpp" #include "dbscan/Point.hpp" #include "TRACE/trace.h" -#include "dunetrigger/triggeralgs/include/triggeralgs/Types.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Types.hpp" #include #include #define TRACE_NAME "TriggerActivityMakerDBSCANPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerActivityMakerHorizontalMuon.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerHorizontalMuon.cpp similarity index 99% rename from dunetrigger/triggeralgs/src/TriggerActivityMakerHorizontalMuon.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerHorizontalMuon.cpp index f8222b6..1419e74 100644 --- a/dunetrigger/triggeralgs/src/TriggerActivityMakerHorizontalMuon.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerHorizontalMuon.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/HorizontalMuon/TriggerActivityMakerHorizontalMuon.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/HorizontalMuon/TriggerActivityMakerHorizontalMuon.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerActivityMakerHorizontalMuonPlugin" #include diff --git a/dunetrigger/triggeralgs/src/TriggerActivityMakerMichelElectron.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerMichelElectron.cpp similarity index 99% rename from dunetrigger/triggeralgs/src/TriggerActivityMakerMichelElectron.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerMichelElectron.cpp index 72cf222..efe74d1 100644 --- a/dunetrigger/triggeralgs/src/TriggerActivityMakerMichelElectron.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerMichelElectron.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/MichelElectron/TriggerActivityMakerMichelElectron.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/MichelElectron/TriggerActivityMakerMichelElectron.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerActivityMakerMichelElectronPlugin" #include diff --git a/dunetrigger/triggeralgs/src/TriggerActivityMakerPlaneCoincidence.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerPlaneCoincidence.cpp similarity index 98% rename from dunetrigger/triggeralgs/src/TriggerActivityMakerPlaneCoincidence.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerPlaneCoincidence.cpp index a4c5de4..d6d1417 100644 --- a/dunetrigger/triggeralgs/src/TriggerActivityMakerPlaneCoincidence.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerPlaneCoincidence.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/PlaneCoincidence/TriggerActivityMakerPlaneCoincidence.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/PlaneCoincidence/TriggerActivityMakerPlaneCoincidence.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerActivityMakerPlaneCoincidencePlugin" #include diff --git a/dunetrigger/triggeralgs/src/TriggerActivityMakerPrescale.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerPrescale.cpp similarity index 94% rename from dunetrigger/triggeralgs/src/TriggerActivityMakerPrescale.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerPrescale.cpp index 1885931..ce31287 100644 --- a/dunetrigger/triggeralgs/src/TriggerActivityMakerPrescale.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerPrescale.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/Prescale/TriggerActivityMakerPrescale.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Prescale/TriggerActivityMakerPrescale.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerActivityMakerPrescalePlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerActivityMakerSupernova.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerSupernova.cpp similarity index 95% rename from dunetrigger/triggeralgs/src/TriggerActivityMakerSupernova.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerSupernova.cpp index c5301af..9c15c6c 100644 --- a/dunetrigger/triggeralgs/src/TriggerActivityMakerSupernova.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerActivityMakerSupernova.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerActivityMakerSupernova.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerActivityMakerSupernova.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerActivityMakerSupernovaPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerCandidateMakerADCSimpleWindow.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerADCSimpleWindow.cpp similarity index 94% rename from dunetrigger/triggeralgs/src/TriggerCandidateMakerADCSimpleWindow.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerADCSimpleWindow.cpp index 19d48ca..8f315e2 100644 --- a/dunetrigger/triggeralgs/src/TriggerCandidateMakerADCSimpleWindow.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerADCSimpleWindow.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/ADCSimpleWindow/TriggerCandidateMakerADCSimpleWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ADCSimpleWindow/TriggerCandidateMakerADCSimpleWindow.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerCandidateMakerADCSimpleWindowPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerCandidateMakerBundleN.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerBundleN.cpp similarity index 95% rename from dunetrigger/triggeralgs/src/TriggerCandidateMakerBundleN.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerBundleN.cpp index 5b6f8b3..7b43c3f 100644 --- a/dunetrigger/triggeralgs/src/TriggerCandidateMakerBundleN.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerBundleN.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/BundleN/TriggerCandidateMakerBundleN.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/BundleN/TriggerCandidateMakerBundleN.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerCandidateMakerBundleNPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerCandidateMakerChannelAdjacency.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerChannelAdjacency.cpp similarity index 96% rename from dunetrigger/triggeralgs/src/TriggerCandidateMakerChannelAdjacency.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerChannelAdjacency.cpp index 13e84d0..238d1b7 100644 --- a/dunetrigger/triggeralgs/src/TriggerCandidateMakerChannelAdjacency.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerChannelAdjacency.cpp @@ -6,8 +6,8 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/ChannelAdjacency/TriggerCandidateMakerChannelAdjacency.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/Logging.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelAdjacency/TriggerCandidateMakerChannelAdjacency.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Logging.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerCandidateMakerChannelAdjacencyPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerCandidateMakerChannelDistance.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerChannelDistance.cpp similarity index 94% rename from dunetrigger/triggeralgs/src/TriggerCandidateMakerChannelDistance.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerChannelDistance.cpp index 83de9d0..b8e7251 100644 --- a/dunetrigger/triggeralgs/src/TriggerCandidateMakerChannelDistance.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerChannelDistance.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/ChannelDistance/TriggerCandidateMakerChannelDistance.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/ChannelDistance/TriggerCandidateMakerChannelDistance.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerCandidateMakerChannelDistancePlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerCandidateMakerDBSCAN.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerDBSCAN.cpp similarity index 94% rename from dunetrigger/triggeralgs/src/TriggerCandidateMakerDBSCAN.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerDBSCAN.cpp index 0364b48..e10b420 100644 --- a/dunetrigger/triggeralgs/src/TriggerCandidateMakerDBSCAN.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerDBSCAN.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/dbscan/TriggerCandidateMakerDBSCAN.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/TriggerCandidateMakerDBSCAN.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerCandidateMakerDBSCANPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerCandidateMakerHorizontalMuon.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerHorizontalMuon.cpp similarity index 98% rename from dunetrigger/triggeralgs/src/TriggerCandidateMakerHorizontalMuon.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerHorizontalMuon.cpp index f6b3aba..6b24f1e 100644 --- a/dunetrigger/triggeralgs/src/TriggerCandidateMakerHorizontalMuon.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerHorizontalMuon.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/HorizontalMuon/TriggerCandidateMakerHorizontalMuon.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/HorizontalMuon/TriggerCandidateMakerHorizontalMuon.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerCandidateMakerHorizontalMuonPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerCandidateMakerMichelElectron.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerMichelElectron.cpp similarity index 98% rename from dunetrigger/triggeralgs/src/TriggerCandidateMakerMichelElectron.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerMichelElectron.cpp index 6321d9a..bd02fba 100644 --- a/dunetrigger/triggeralgs/src/TriggerCandidateMakerMichelElectron.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerMichelElectron.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/MichelElectron/TriggerCandidateMakerMichelElectron.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/MichelElectron/TriggerCandidateMakerMichelElectron.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerCandidateMakerMichelElectronPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerCandidateMakerPlaneCoincidence.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerPlaneCoincidence.cpp similarity index 98% rename from dunetrigger/triggeralgs/src/TriggerCandidateMakerPlaneCoincidence.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerPlaneCoincidence.cpp index 665faf4..91beb74 100644 --- a/dunetrigger/triggeralgs/src/TriggerCandidateMakerPlaneCoincidence.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerPlaneCoincidence.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/PlaneCoincidence/TriggerCandidateMakerPlaneCoincidence.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/PlaneCoincidence/TriggerCandidateMakerPlaneCoincidence.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerCandidateMakerPlaneCoincidencePlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerCandidateMakerPrescale.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerPrescale.cpp similarity index 94% rename from dunetrigger/triggeralgs/src/TriggerCandidateMakerPrescale.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerPrescale.cpp index fafd717..4e37012 100644 --- a/dunetrigger/triggeralgs/src/TriggerCandidateMakerPrescale.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerPrescale.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/Prescale/TriggerCandidateMakerPrescale.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Prescale/TriggerCandidateMakerPrescale.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerCandidateMakerPrescalePlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerCandidateMakerSupernova.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerSupernova.cpp similarity index 93% rename from dunetrigger/triggeralgs/src/TriggerCandidateMakerSupernova.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerSupernova.cpp index 45920b6..1d31648 100644 --- a/dunetrigger/triggeralgs/src/TriggerCandidateMakerSupernova.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerCandidateMakerSupernova.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerCandidateMakerSupernova.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerCandidateMakerSupernova.hpp" #include "TRACE/trace.h" #define TRACE_NAME "TriggerCandidateMakerSupernovaPlugin" diff --git a/dunetrigger/triggeralgs/src/TriggerDecisionMakerSupernova.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerDecisionMakerSupernova.cpp similarity index 91% rename from dunetrigger/triggeralgs/src/TriggerDecisionMakerSupernova.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerDecisionMakerSupernova.cpp index b7a079e..bed8e05 100644 --- a/dunetrigger/triggeralgs/src/TriggerDecisionMakerSupernova.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/TriggerDecisionMakerSupernova.cpp @@ -6,7 +6,7 @@ * received with this code. */ -#include "dunetrigger/triggeralgs/include/triggeralgs/Supernova/TriggerDecisionMakerSupernova.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/Supernova/TriggerDecisionMakerSupernova.hpp" #include #include diff --git a/dunetrigger/triggeralgs/src/dbscan/Hit.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/dbscan/Hit.cpp similarity index 96% rename from dunetrigger/triggeralgs/src/dbscan/Hit.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/dbscan/Hit.cpp index 60f2815..a0ef502 100644 --- a/dunetrigger/triggeralgs/src/dbscan/Hit.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/dbscan/Hit.cpp @@ -1,4 +1,4 @@ -#include "dunetrigger/triggeralgs/include/triggeralgs/dbscan/Hit.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/Hit.hpp" #include diff --git a/dunetrigger/triggeralgs/src/dbscan/Point.hpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/dbscan/Point.hpp similarity index 100% rename from dunetrigger/triggeralgs/src/dbscan/Point.hpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/dbscan/Point.hpp diff --git a/dunetrigger/triggeralgs/src/dbscan/dbscan.cpp b/dunetrigger/TriggerSim/triggeralgs/v4/src/dbscan/dbscan.cpp similarity index 98% rename from dunetrigger/triggeralgs/src/dbscan/dbscan.cpp rename to dunetrigger/TriggerSim/triggeralgs/v4/src/dbscan/dbscan.cpp index ecdc5d4..114eee0 100644 --- a/dunetrigger/triggeralgs/src/dbscan/dbscan.cpp +++ b/dunetrigger/TriggerSim/triggeralgs/v4/src/dbscan/dbscan.cpp @@ -1,5 +1,5 @@ -#include "dunetrigger/triggeralgs/include/triggeralgs/dbscan/dbscan.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/dbscan/Hit.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/dbscan.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/dbscan/Hit.hpp" #include #include From 99e92ea124f07efb57c7fdb6aa6b61de238800d3 Mon Sep 17 00:00:00 2001 From: James Shen Date: Fri, 18 Jul 2025 16:53:10 -0400 Subject: [PATCH 2/7] Make TAM and TCM v4 specific --- ...le.cc => TriggerActivityMakerV4_module.cc} | 37 +++++++++---------- ...e.cc => TriggerCandidateMakerV4_module.cc} | 37 +++++++++---------- .../TriggerSim/fcl/triggersim_makers.fcl | 6 +-- 3 files changed, 37 insertions(+), 43 deletions(-) rename dunetrigger/TriggerSim/{TriggerActivityMakerTPC_module.cc => TriggerActivityMakerV4_module.cc} (92%) rename dunetrigger/TriggerSim/{TriggerCandidateMakerTPC_module.cc => TriggerCandidateMakerV4_module.cc} (88%) diff --git a/dunetrigger/TriggerSim/TriggerActivityMakerTPC_module.cc b/dunetrigger/TriggerSim/TriggerActivityMakerV4_module.cc similarity index 92% rename from dunetrigger/TriggerSim/TriggerActivityMakerTPC_module.cc rename to dunetrigger/TriggerSim/TriggerActivityMakerV4_module.cc index f311819..53d422a 100644 --- a/dunetrigger/TriggerSim/TriggerActivityMakerTPC_module.cc +++ b/dunetrigger/TriggerSim/TriggerActivityMakerV4_module.cc @@ -1,10 +1,7 @@ //////////////////////////////////////////////////////////////////////// -// Class: TriggerActivityMakerTPC +// Class: TriggerActivityMakerV4 // Plugin Type: producer (Unknown Unknown) -// File: TriggerActivityMakerTPC_module.cc -// -// Generated at Tue Aug 13 11:03:40 2024 by ddrobner using cetskelgen -// from cetlib version 3.18.02. +// File: TriggerActivityMakerV4_module.cc //////////////////////////////////////////////////////////////////////// #include "art/Framework/Core/EDProducer.h" @@ -25,8 +22,8 @@ #include "dunetrigger/TriggerSim/Verbosity.hh" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivity.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerActivityFactory.hpp" #include #include @@ -37,7 +34,7 @@ #include namespace dunetrigger { -class TriggerActivityMakerTPC; +class TriggerActivityMakerV4; typedef std::pair TAMakerScopeID_t; std::ostream &operator<<(std::ostream &os, @@ -53,19 +50,19 @@ static TAMakerScopeID_t getTAScopeID(readout::ROPID &ropid, } } // namespace dunetrigger -class dunetrigger::TriggerActivityMakerTPC : public art::EDProducer { +class dunetrigger::TriggerActivityMakerV4 : public art::EDProducer { public: - explicit TriggerActivityMakerTPC(fhicl::ParameterSet const &p); + explicit TriggerActivityMakerV4(fhicl::ParameterSet const &p); // The compiler-generated destructor is fine for non-base // classes without bare pointers or other resource use. // Plugins should not be copied or assigned. - TriggerActivityMakerTPC(TriggerActivityMakerTPC const &) = delete; - TriggerActivityMakerTPC(TriggerActivityMakerTPC &&) = delete; - TriggerActivityMakerTPC & - operator=(TriggerActivityMakerTPC const &) = delete; - TriggerActivityMakerTPC & - operator=(TriggerActivityMakerTPC &&) = delete; + TriggerActivityMakerV4(TriggerActivityMakerV4 const &) = delete; + TriggerActivityMakerV4(TriggerActivityMakerV4 &&) = delete; + TriggerActivityMakerV4 & + operator=(TriggerActivityMakerV4 const &) = delete; + TriggerActivityMakerV4 & + operator=(TriggerActivityMakerV4 &&) = delete; void beginJob() override; void produce(art::Event &e) override; @@ -139,7 +136,7 @@ class dunetrigger::TriggerActivityMakerTPC : public art::EDProducer { } }; -dunetrigger::TriggerActivityMakerTPC::TriggerActivityMakerTPC( +dunetrigger::TriggerActivityMakerV4::TriggerActivityMakerV4( fhicl::ParameterSet const &p) : EDProducer{p}, algname(p.get("algorithm")), algconfig_plane0(p.get("algconfig_plane0")), @@ -160,7 +157,7 @@ dunetrigger::TriggerActivityMakerTPC::TriggerActivityMakerTPC( consumes>(tp_tag); } -void dunetrigger::TriggerActivityMakerTPC::beginJob() { +void dunetrigger::TriggerActivityMakerV4::beginJob() { // nice printout of channel mask if (verbosity >= Verbosity::kInfo) { std::cout << "Masked Channels:"; @@ -174,7 +171,7 @@ void dunetrigger::TriggerActivityMakerTPC::beginJob() { } } -void dunetrigger::TriggerActivityMakerTPC::produce(art::Event &e) { +void dunetrigger::TriggerActivityMakerV4::produce(art::Event &e) { // these things end up getting written about 5000 times, so let's do this here using dunedaq::trgdataformats::TriggerActivityData; using dunedaq::trgdataformats::TriggerPrimitive; @@ -329,4 +326,4 @@ void dunetrigger::TriggerActivityMakerTPC::produce(art::Event &e) { e.put(std::move(tp_in_tas_assn_ptr)); } -DEFINE_ART_MODULE(dunetrigger::TriggerActivityMakerTPC) +DEFINE_ART_MODULE(dunetrigger::TriggerActivityMakerV4) diff --git a/dunetrigger/TriggerSim/TriggerCandidateMakerTPC_module.cc b/dunetrigger/TriggerSim/TriggerCandidateMakerV4_module.cc similarity index 88% rename from dunetrigger/TriggerSim/TriggerCandidateMakerTPC_module.cc rename to dunetrigger/TriggerSim/TriggerCandidateMakerV4_module.cc index 669b09d..4b6ab56 100644 --- a/dunetrigger/TriggerSim/TriggerCandidateMakerTPC_module.cc +++ b/dunetrigger/TriggerSim/TriggerCandidateMakerV4_module.cc @@ -1,10 +1,7 @@ //////////////////////////////////////////////////////////////////////// -// Class: TriggerCandidateMakerTPC +// Class: TriggerCandidateMakerV4 // Plugin Type: producer (Unknown Unknown) -// File: TriggerCandidateMakerTPC_module.cc -// -// Generated at Tue Aug 13 16:43:32 2024 by ddrobner using cetskelgen -// from cetlib version 3.18.02. +// File: TriggerCandidateMakerV4_module.cc //////////////////////////////////////////////////////////////////////// #include "art/Framework/Core/EDProducer.h" @@ -22,8 +19,8 @@ #include "fhiclcpp/ParameterSet.h" #include "messagefacility/MessageLogger/MessageLogger.h" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidate.hpp" -#include "dunetrigger/triggeralgs/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidate.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v4/include/triggeralgs/TriggerCandidateFactory.hpp" #include "detdataformats/trigger/TriggerActivityData.hpp" #include "detdataformats/trigger/TriggerCandidateData.hpp" @@ -58,23 +55,23 @@ struct ExtTriggerActivity : public TriggerActivity { } // namespace triggeralgs namespace dunetrigger { -class TriggerCandidateMakerTPC; +class TriggerCandidateMakerV4; } -class dunetrigger::TriggerCandidateMakerTPC : public art::EDProducer { +class dunetrigger::TriggerCandidateMakerV4 : public art::EDProducer { public: - explicit TriggerCandidateMakerTPC(fhicl::ParameterSet const &p); + explicit TriggerCandidateMakerV4(fhicl::ParameterSet const &p); // The compiler-generated destructor is fine for non-base // classes without bare pointers or other resource use. // Plugins should not be copied or assigned. - TriggerCandidateMakerTPC(TriggerCandidateMakerTPC const &) = + TriggerCandidateMakerV4(TriggerCandidateMakerV4 const &) = delete; - TriggerCandidateMakerTPC(TriggerCandidateMakerTPC &&) = delete; - TriggerCandidateMakerTPC & - operator=(TriggerCandidateMakerTPC const &) = delete; - TriggerCandidateMakerTPC & - operator=(TriggerCandidateMakerTPC &&) = delete; + TriggerCandidateMakerV4(TriggerCandidateMakerV4 &&) = delete; + TriggerCandidateMakerV4 & + operator=(TriggerCandidateMakerV4 const &) = delete; + TriggerCandidateMakerV4 & + operator=(TriggerCandidateMakerV4 &&) = delete; void beginJob() override; void produce(art::Event &e) override; @@ -109,7 +106,7 @@ class dunetrigger::TriggerCandidateMakerTPC : public art::EDProducer { } }; -dunetrigger::TriggerCandidateMakerTPC::TriggerCandidateMakerTPC( +dunetrigger::TriggerCandidateMakerV4::TriggerCandidateMakerV4( fhicl::ParameterSet const &p) : EDProducer{p}, ta_tag(p.get("ta_tag")), algname(p.get("algorithm")), @@ -123,7 +120,7 @@ dunetrigger::TriggerCandidateMakerTPC::TriggerCandidateMakerTPC( produces>(); } -void dunetrigger::TriggerCandidateMakerTPC::beginJob() { +void dunetrigger::TriggerCandidateMakerV4::beginJob() { // build alg using the factory alg = alg_factory->build_maker(algname); @@ -147,7 +144,7 @@ void dunetrigger::TriggerCandidateMakerTPC::beginJob() { alg->configure(alg_json); } -void dunetrigger::TriggerCandidateMakerTPC::produce(art::Event &e) { +void dunetrigger::TriggerCandidateMakerV4::produce(art::Event &e) { using dunedaq::trgdataformats::TriggerActivityData; using dunedaq::trgdataformats::TriggerCandidateData; @@ -246,4 +243,4 @@ void dunetrigger::TriggerCandidateMakerTPC::produce(art::Event &e) { e.put(std::move(ta_in_tc_assn_ptr)); } -DEFINE_ART_MODULE(dunetrigger::TriggerCandidateMakerTPC) +DEFINE_ART_MODULE(dunetrigger::TriggerCandidateMakerV4) diff --git a/dunetrigger/TriggerSim/fcl/triggersim_makers.fcl b/dunetrigger/TriggerSim/fcl/triggersim_makers.fcl index bc3b3f9..703a140 100644 --- a/dunetrigger/TriggerSim/fcl/triggersim_makers.fcl +++ b/dunetrigger/TriggerSim/fcl/triggersim_makers.fcl @@ -47,7 +47,7 @@ nmodules_dune10kt_1x2x2: 4 # 4 APAs in the middle tamakerTPC_ADCSimpleWindow: { - module_type: TriggerActivityMakerTPC + module_type: TriggerActivityMakerV4 tp_tag: "tpmakerTPC" # simple window, see trgdataformats/include/trgdataformats/TriggerActivityData.hpp algorithm: "TriggerActivityMakerADCSimpleWindowPlugin" # another basic option is TriggerActivityMakerChannelAdjacencyPlugin @@ -89,7 +89,7 @@ tcconfig_simplewindow: tcmakerTPC_ADCSimpleWindow: { - module_type: TriggerCandidateMakerTPC + module_type: TriggerCandidateMakerV4 ta_tag: "tamakerTPC" algorithm: "TriggerCandidateMakerADCSimpleWindowPlugin" algconfig: @local::tcconfig_simplewindow @@ -97,4 +97,4 @@ tcmakerTPC_ADCSimpleWindow: verbosity: 1 } -END_PROLOG \ No newline at end of file +END_PROLOG From 3f10e9a284c91ca4d45f0bd6b76d103682689f30 Mon Sep 17 00:00:00 2001 From: James Shen Date: Fri, 18 Jul 2025 17:09:43 -0400 Subject: [PATCH 3/7] Stop using an inheritance to solve a partial copy problem --- .../TriggerCandidateMakerV4_module.cc | 30 ++++--------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/dunetrigger/TriggerSim/TriggerCandidateMakerV4_module.cc b/dunetrigger/TriggerSim/TriggerCandidateMakerV4_module.cc index 4b6ab56..f319c9a 100644 --- a/dunetrigger/TriggerSim/TriggerCandidateMakerV4_module.cc +++ b/dunetrigger/TriggerSim/TriggerCandidateMakerV4_module.cc @@ -34,26 +34,6 @@ #include #include -namespace triggeralgs { -struct ExtTriggerActivity : public TriggerActivity { - ExtTriggerActivity(const dunedaq::trgdataformats::TriggerActivityData &data) { - this->time_start = data.time_start; - this->time_end = data.time_end; - this->time_peak = data.time_peak; - this->time_activity = data.time_activity; - this->channel_start = data.channel_start; - this->channel_end = data.channel_end; - this->channel_peak = data.channel_peak; - this->adc_integral = data.adc_integral; - this->adc_peak = data.adc_peak; - this->detid = data.detid; - this->type = data.type; - this->algorithm = data.algorithm; - this->version = data.version; - } -}; -} // namespace triggeralgs - namespace dunetrigger { class TriggerCandidateMakerV4; } @@ -187,10 +167,12 @@ void dunetrigger::TriggerCandidateMakerV4::produce(art::Event &e) { std::vector produced_tcs = {}; // process the input TAs - for (const auto &ta : input_tas) { - dunedaq::trgdataformats::TriggerActivityData ta_data = ta.second; - triggeralgs::ExtTriggerActivity ta_ext(ta_data); - (*alg)(ta_ext, produced_tcs); + for (const auto &ta_indexed : input_tas) { + dunedaq::trgdataformats::TriggerActivityData ta_data = ta_indexed.second; + triggeralgs::TriggerActivity curr_ta; + static_cast(curr_ta) = + ta_data; + (*alg)(curr_ta, produced_tcs); } // now we need to handle the associations From 7882d78bc5fd4d3edc4fb88c879a72dd56387031 Mon Sep 17 00:00:00 2001 From: James Shen Date: Mon, 21 Jul 2025 15:53:58 -0400 Subject: [PATCH 4/7] Add triggeralgs from DUNEDAQv5 --- dunetrigger/TriggerAna/CMakeLists.txt | 3 +- dunetrigger/TriggerSim/CMakeLists.txt | 3 +- .../TriggerSim/triggeralgs/CMakeLists.txt | 1 + .../TriggerSim/triggeralgs/v4/CMakeLists.txt | 2 +- .../v5/.github/workflows/auto_approve.yml | 19 + .../workflows/dunedaq-develop-cpp-ci.yml | 24 ++ .../v5/.github/workflows/track_new_issues.yml | 12 + .../v5/.github/workflows/track_new_prs.yml | 12 + .../TriggerSim/triggeralgs/v5/.gitignore | 3 + .../TriggerSim/triggeralgs/v5/CMakeLists.txt | 37 ++ .../triggeralgs/v5/README-DUNEDAQ.md | 160 ++++++++ .../TriggerSim/triggeralgs/v5/README.md | 3 + .../triggeralgs/v5/autogen/CMakeLists.txt | 28 ++ .../triggeralgs/v5/autogen/main.cxx.in | 12 + .../v5/cmake/triggeralgsConfig.cmake.in | 30 ++ .../cmake/triggeralgsConfigVersion.cmake.in | 11 + .../triggeralgs/v5/exec/CMakeLists.txt | 8 + .../v5/exec/NaiveTriggerCandidateConsumer.h | 67 +++ .../triggeralgs/v5/exec/NaiveTriggerQueue.h | 121 ++++++ .../triggeralgs/v5/exec/compile_me.cxx | 28 ++ .../v5/exec/run_trivial_candidate.cxx | 124 ++++++ .../triggeralgs/v5/include/CMakeLists.txt | 1 + .../ADCSimpleWindow/AlgorithmFlowChart.png | Bin 0 -> 80185 bytes .../triggeralgs/ADCSimpleWindow/README.md | 32 ++ .../TAMakerADCSimpleWindowAlgorithm.hpp | 100 +++++ .../TCMakerADCSimpleWindowAlgorithm.hpp | 34 ++ .../include/triggeralgs/AbstractFactory.hpp | 49 +++ .../include/triggeralgs/AbstractFactory.hxx | 64 +++ .../BundleN/TAMakerBundleNAlgorithm.hpp | 33 ++ .../BundleN/TCMakerBundleNAlgorithm.hpp | 33 ++ .../triggeralgs/ChannelAdjacency/README.md | 3 + .../TAMakerChannelAdjacencyAlgorithm.hpp | 42 ++ .../TCMakerChannelAdjacencyAlgorithm.hpp | 46 +++ .../TAMakerChannelDistanceAlgorithm.hpp | 35 ++ .../TCMakerChannelDistanceAlgorithm.hpp | 32 ++ .../triggeralgs/HorizontalMuon/README.md | 4 + .../TAMakerHorizontalMuonAlgorithm.hpp | 55 +++ .../TCMakerHorizontalMuonAlgorithm.hpp | 49 +++ .../v5/include/triggeralgs/Issues.hpp | 38 ++ .../v5/include/triggeralgs/Logging.hpp | 30 ++ .../triggeralgs/MichelElectron/README.md | 4 + .../TAMakerMichelElectronAlgorithm.hpp | 133 ++++++ .../TCMakerMichelElectronAlgorithm.hpp | 152 +++++++ .../triggeralgs/PlaneCoincidence/README.md | 27 ++ .../TAMakerPlaneCoincidenceAlgorithm.hpp | 68 ++++ .../TCMakerPlaneCoincidenceAlgorithm.hpp | 48 +++ .../Prescale/TAMakerPrescaleAlgorithm.hpp | 29 ++ .../Prescale/TCMakerPrescaleAlgorithm.hpp | 32 ++ .../Supernova/TAMakerSupernovaAlgorithm.hpp | 99 +++++ .../Supernova/TCMakerSupernovaAlgorithm.hpp | 51 +++ .../Supernova/TDMakerSupernovaAlgorithm.hpp | 50 +++ .../v5/include/triggeralgs/TAWindow.hpp | 60 +++ .../v5/include/triggeralgs/TPWindow.hpp | 44 ++ .../include/triggeralgs/TriggerActivity.hpp | 37 ++ .../triggeralgs/TriggerActivityFactory.hpp | 27 ++ .../triggeralgs/TriggerActivityMaker.hpp | 141 +++++++ .../include/triggeralgs/TriggerCandidate.hpp | 37 ++ .../triggeralgs/TriggerCandidateFactory.hpp | 27 ++ .../triggeralgs/TriggerCandidateMaker.hpp | 144 +++++++ .../include/triggeralgs/TriggerDecision.hpp | 35 ++ .../triggeralgs/TriggerDecisionMaker.hpp | 35 ++ .../triggeralgs/TriggerObjectOverlay.hpp | 115 ++++++ .../include/triggeralgs/TriggerPrimitive.hpp | 26 ++ .../triggeralgs/TriggerPrimitiveMaker.hpp | 32 ++ .../v5/include/triggeralgs/Types.hpp | 26 ++ .../v5/include/triggeralgs/dbscan/Hit.hpp | 131 ++++++ .../dbscan/TAMakerDBSCANAlgorithm.hpp | 37 ++ .../dbscan/TCMakerDBSCANAlgorithm.hpp | 35 ++ .../v5/include/triggeralgs/dbscan/dbscan.hpp | 112 +++++ .../src/TAMakerADCSimpleWindowAlgorithm.cpp | 108 +++++ .../v5/src/TAMakerBundleNAlgorithm.cpp | 87 ++++ .../src/TAMakerChannelAdjacencyAlgorithm.cpp | 241 +++++++++++ .../src/TAMakerChannelDistanceAlgorithm.cpp | 104 +++++ .../v5/src/TAMakerDBSCANAlgorithm.cpp | 91 +++++ .../v5/src/TAMakerHorizontalMuonAlgorithm.cpp | 338 ++++++++++++++++ .../v5/src/TAMakerMichelElectronAlgorithm.cpp | 382 ++++++++++++++++++ .../src/TAMakerPlaneCoincidenceAlgorithm.cpp | 273 +++++++++++++ .../v5/src/TAMakerPrescaleAlgorithm.cpp | 53 +++ .../v5/src/TAMakerSupernovaAlgorithm.cpp | 87 ++++ .../triggeralgs/v5/src/TAWindow.cpp | 117 ++++++ .../src/TCMakerADCSimpleWindowAlgorithm.cpp | 45 +++ .../v5/src/TCMakerBundleNAlgorithm.cpp | 73 ++++ .../src/TCMakerChannelAdjacencyAlgorithm.cpp | 143 +++++++ .../src/TCMakerChannelDistanceAlgorithm.cpp | 80 ++++ .../v5/src/TCMakerDBSCANAlgorithm.cpp | 77 ++++ .../v5/src/TCMakerHorizontalMuonAlgorithm.cpp | 218 ++++++++++ .../v5/src/TCMakerMichelElectronAlgorithm.cpp | 214 ++++++++++ .../src/TCMakerPlaneCoincidenceAlgorithm.cpp | 184 +++++++++ .../v5/src/TCMakerPrescaleAlgorithm.cpp | 50 +++ .../v5/src/TCMakerSupernovaAlgorithm.cpp | 44 ++ .../v5/src/TDMakerSupernovaAlgorithm.cpp | 45 +++ .../triggeralgs/v5/src/TPWindow.cpp | 109 +++++ .../triggeralgs/v5/src/dbscan/Hit.cpp | 83 ++++ .../triggeralgs/v5/src/dbscan/Point.hpp | 11 + .../triggeralgs/v5/src/dbscan/dbscan.cpp | 325 +++++++++++++++ .../triggeralgs/v5/test/CMakeLists.txt | 4 + .../triggeralgs/v5/test/test_factory.cxx | 46 +++ .../channelmaps/OfflineTPCChannelMap.hpp | 3 +- 98 files changed, 6813 insertions(+), 4 deletions(-) create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/auto_approve.yml create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/dunedaq-develop-cpp-ci.yml create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/track_new_issues.yml create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/track_new_prs.yml create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/.gitignore create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/CMakeLists.txt create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/README-DUNEDAQ.md create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/README.md create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/autogen/CMakeLists.txt create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/autogen/main.cxx.in create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/cmake/triggeralgsConfig.cmake.in create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/cmake/triggeralgsConfigVersion.cmake.in create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/exec/CMakeLists.txt create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/exec/NaiveTriggerCandidateConsumer.h create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/exec/NaiveTriggerQueue.h create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/exec/compile_me.cxx create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/exec/run_trivial_candidate.cxx create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/CMakeLists.txt create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/AlgorithmFlowChart.png create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/README.md create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/TAMakerADCSimpleWindowAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/TCMakerADCSimpleWindowAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hxx create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/BundleN/TAMakerBundleNAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/BundleN/TCMakerBundleNAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/README.md create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/TAMakerChannelAdjacencyAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/TCMakerChannelAdjacencyAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelDistance/TAMakerChannelDistanceAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelDistance/TCMakerChannelDistanceAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/README.md create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/TAMakerHorizontalMuonAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/TCMakerHorizontalMuonAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Issues.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Logging.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/README.md create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/TAMakerMichelElectronAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/TCMakerMichelElectronAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/README.md create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/TAMakerPlaneCoincidenceAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/TCMakerPlaneCoincidenceAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Prescale/TAMakerPrescaleAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Prescale/TCMakerPrescaleAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TAMakerSupernovaAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TCMakerSupernovaAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TDMakerSupernovaAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TAWindow.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TPWindow.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivity.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityMaker.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidate.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateMaker.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerDecision.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerDecisionMaker.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerObjectOverlay.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitiveMaker.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/Hit.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/TAMakerDBSCANAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/TCMakerDBSCANAlgorithm.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/dbscan.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerADCSimpleWindowAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerBundleNAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerChannelAdjacencyAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerChannelDistanceAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerDBSCANAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerHorizontalMuonAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerMichelElectronAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerPlaneCoincidenceAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerPrescaleAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerSupernovaAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TAWindow.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerADCSimpleWindowAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerBundleNAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerChannelAdjacencyAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerChannelDistanceAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerDBSCANAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerHorizontalMuonAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerMichelElectronAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerPlaneCoincidenceAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerPrescaleAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerSupernovaAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TDMakerSupernovaAlgorithm.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/TPWindow.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/Hit.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/Point.hpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/dbscan.cpp create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/test/CMakeLists.txt create mode 100644 dunetrigger/TriggerSim/triggeralgs/v5/test/test_factory.cxx diff --git a/dunetrigger/TriggerAna/CMakeLists.txt b/dunetrigger/TriggerAna/CMakeLists.txt index 90e4eb8..82a7fef 100644 --- a/dunetrigger/TriggerAna/CMakeLists.txt +++ b/dunetrigger/TriggerAna/CMakeLists.txt @@ -21,7 +21,8 @@ art_make(BASENAME_ONLY MODULE_LIBRARIES cetlib::cetlib cetlib_except::cetlib_except ROOT::Tree - triggeralgs_module + triggeralgs_v4_module + triggeralgs_v5_module ) diff --git a/dunetrigger/TriggerSim/CMakeLists.txt b/dunetrigger/TriggerSim/CMakeLists.txt index e507a68..c46f104 100644 --- a/dunetrigger/TriggerSim/CMakeLists.txt +++ b/dunetrigger/TriggerSim/CMakeLists.txt @@ -23,7 +23,8 @@ art_make( BASENAME_ONLY MODULE_LIBRARIES cetlib::cetlib cetlib_except::cetlib_except ROOT::Tree - triggeralgs_module + triggeralgs_v4_module + triggeralgs_v5_module ) install_fhicl() diff --git a/dunetrigger/TriggerSim/triggeralgs/CMakeLists.txt b/dunetrigger/TriggerSim/triggeralgs/CMakeLists.txt index 194866c..64d2412 100644 --- a/dunetrigger/TriggerSim/triggeralgs/CMakeLists.txt +++ b/dunetrigger/TriggerSim/triggeralgs/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(v4) +add_subdirectory(v5) diff --git a/dunetrigger/TriggerSim/triggeralgs/v4/CMakeLists.txt b/dunetrigger/TriggerSim/triggeralgs/v4/CMakeLists.txt index a6fe2f4..089b5ca 100644 --- a/dunetrigger/TriggerSim/triggeralgs/v4/CMakeLists.txt +++ b/dunetrigger/TriggerSim/triggeralgs/v4/CMakeLists.txt @@ -3,7 +3,7 @@ add_compile_options(-O2 -flto -Wno-error=sign-compare -Wno-error=unused-variable include(BasicPlugin) include_directories("${dunedetdataformats_DIR}/../../../include") -basic_plugin(triggeralgs module +basic_plugin(triggeralgs_v4 module BASENAME_ONLY LIBRARIES OfflineTPCChannelMap_module diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/auto_approve.yml b/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/auto_approve.yml new file mode 100644 index 0000000..428715f --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/auto_approve.yml @@ -0,0 +1,19 @@ +name: Auto approve + +on: + workflow_dispatch: + inputs: + pullRequestNumber: + description: Pull request number to auto-approve + required: false + +jobs: + auto-approve: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - uses: hmarr/auto-approve-action@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + pull-request-number: ${{ github.event.inputs.pullRequestNumber }} diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/dunedaq-develop-cpp-ci.yml b/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/dunedaq-develop-cpp-ci.yml new file mode 100644 index 0000000..4bd89a6 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/dunedaq-develop-cpp-ci.yml @@ -0,0 +1,24 @@ +name: build-develop + +# Controls when the action will run. Workflow runs when manually triggered using the UI +# or API. +on: + push: + branches: + - develop + - patch/* + - prep-release/* + paths-ignore: + - 'docs/**' + - '.github/**' + pull_request: + branches: [ develop ] + schedule: + - cron: "0 9 * * *" + + workflow_dispatch: + +jobs: + build_develop_dispatch: + name: Build against the development release + uses: DUNE-DAQ/.github/.github/workflows/dunedaq-develop-cpp-ci.yml@develop \ No newline at end of file diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/track_new_issues.yml b/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/track_new_issues.yml new file mode 100644 index 0000000..63cd63f --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/track_new_issues.yml @@ -0,0 +1,12 @@ +name: Add issue to project +on: + issues: + types: + - opened + +jobs: + track_issues_dispatch: + name: Add new issue to project + uses: DUNE-DAQ/.github/.github/workflows/track_new_issues.yml@develop + secrets: + BOT_CI_ISSUES: ${{ secrets.BOT_CI_ISSUES }} \ No newline at end of file diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/track_new_prs.yml b/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/track_new_prs.yml new file mode 100644 index 0000000..8f691ee --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/.github/workflows/track_new_prs.yml @@ -0,0 +1,12 @@ +name: Add pull request to project +on: + pull_request: + types: + - opened + +jobs: + track_prs_dispatch: + name: Add new pull request to project + uses: DUNE-DAQ/.github/.github/workflows/track_new_prs.yml@develop + secrets: + BOT_CI_ISSUES: ${{ secrets.BOT_CI_ISSUES }} \ No newline at end of file diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/.gitignore b/dunetrigger/TriggerSim/triggeralgs/v5/.gitignore new file mode 100644 index 0000000..70c9c75 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/.gitignore @@ -0,0 +1,3 @@ +build/ +*~ +.#* \ No newline at end of file diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/CMakeLists.txt b/dunetrigger/TriggerSim/triggeralgs/v5/CMakeLists.txt new file mode 100644 index 0000000..95f348d --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/CMakeLists.txt @@ -0,0 +1,37 @@ +add_compile_options(-O2 -flto -Wno-error=sign-compare -Wno-error=unused-variable) + +include(BasicPlugin) +include_directories("${dunedetdataformats_DIR}/../../../include") + +basic_plugin(triggeralgs_v5 module + BASENAME_ONLY + LIBRARIES + OfflineTPCChannelMap_module + SOURCE + src/TAMakerADCSimpleWindowAlgorithm.cpp + src/TCMakerADCSimpleWindowAlgorithm.cpp + src/TAMakerHorizontalMuonAlgorithm.cpp + src/TCMakerHorizontalMuonAlgorithm.cpp + src/TCMakerPlaneCoincidenceAlgorithm.cpp + src/TAMakerPlaneCoincidenceAlgorithm.cpp + src/TAMakerMichelElectronAlgorithm.cpp + src/TCMakerMichelElectronAlgorithm.cpp + src/TAMakerPrescaleAlgorithm.cpp + src/TCMakerPrescaleAlgorithm.cpp + src/TAMakerSupernovaAlgorithm.cpp + src/TCMakerSupernovaAlgorithm.cpp + src/TDMakerSupernovaAlgorithm.cpp + src/TAMakerDBSCANAlgorithm.cpp + src/TCMakerDBSCANAlgorithm.cpp + src/TAMakerChannelDistanceAlgorithm.cpp + src/TCMakerChannelDistanceAlgorithm.cpp + src/TAMakerBundleNAlgorithm.cpp + src/TCMakerBundleNAlgorithm.cpp + src/TAMakerChannelAdjacencyAlgorithm.cpp + src/TCMakerChannelAdjacencyAlgorithm.cpp + src/TAWindow.cpp + src/TPWindow.cpp + src/dbscan/dbscan.cpp + src/dbscan/Hit.cpp +) + diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/README-DUNEDAQ.md b/dunetrigger/TriggerSim/triggeralgs/v5/README-DUNEDAQ.md new file mode 100644 index 0000000..34539b9 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/README-DUNEDAQ.md @@ -0,0 +1,160 @@ +# triggeralgs +A place to put the trigger algorithms for DUNE. This code can then be +linked inside ArtDAQ and LArSoft, so that we can run the exact same +code in simulation and on real data. + +### TOC + - [Future](#future) + - [Organisation](#organisation) + - [Compile](#compile) + - [Contribute](#contribute) + - [Data structures](#structs) + + + +## Future interesting things to do + - Improve documentation!! + - Make the whole setup more realistic + - TPs from PDFs of what we expect from LArSoft/simulations + - TAs algorithm better + - Find a way to estimate the efficiency for TAs and TCs. + - Implementation of "TP window" and "TP zipper": + - TP window = something that ensures that the TPs are all in a time window, + - TP zipper = something that merges source of TPs. + + + + +## Organisation +The code is quite simple. Essentially, the trigger algorithm rely on 3 +structs: + - `TriggerPrimitive` (also known as hits) + - `TriggerActivity` (clusters) + - `TriggerCandidate` (trigger) + - `TriggerDecision` (readout request ?) + +Their format will be discussed at a DAQ meeting and fixed at some point. + +The trigger primitives are created within ArtDAQ or LArSoft. These are +passed to one or more `TriggerActivityMaker` classes which create the +`TriggerActivity`. The `TriggerActivity` are then passed on to one +or more `TriggerCandidateMaker` classes, which create the +candidates, which in turn will be fed to `TriggerDecisionMaker`, etc. Each rely on their pure virtual operator: + - `void TriggerActivityMaker ::operator()(const TriggerPrimitive& input_tp, std::vector& output_ta)` + - `void TriggerCandidateMaker::operator()(const TriggerActivity& input_ta , std::vector& output_tc)` + - `void TriggerDecisionMaker ::operator()(const TriggerCandidate& input_tc, std::vector& output_td)` + +that any `TriggerActivityMaker`, `TriggerCandidateMaker` and +`TriggerDecisionMaker` need to implement, respectively. + +Note the TPs can also be created here, but given how this happens now +in real life, it doesn't look like these libraries will be used for +creating TPs (the data structures for the raw data are very +complicated and closely tied to ArtDAQ, that is not so much the case +in LArSoft), hence the `TriggerPrimitiveMaker` class exists with its +corresponding operator: +- `void TriggerPrimitiveMaker::operator()(const void* data, std::vector& tps)` + +but that may not necessarily be used. + +These operators do all the work, they should be reasonably +fast to handle the rate at which their input arrive in the real +system. The "makers" get input data, rearrange it, and then +`push_back` to the output vector. An example is available in +`src/trivial/TriggerCandidateMaker_trivial.hh`. It can be tested with +a `exec/run_trivial_candidate.cxx`, which creates fake TPs, feeds +them into it and then dumps them in a csv. + +Note none the granularity of the `TriggerActivityMaker`, +`TriggerCandidateMaker` and `TriggerDecisionMaker` isn't be decided here. +It is the ArtDAQ's developers' job to decided how many +`TriggerCandidateMakers` there should be in one APA for example. The +focus of this library is the algorithm, ArtDAQ should +create and handle the DuneTriggers objects and the calls to them (this is realised in triggermodules) + + + +## To compile it +You need to have the boost libraries for testing (this dependency will be dropped soon, we don't need it) +``` +git clone https://github.com/DUNE-DAQ/triggeralgs.git +cd triggeralgs +mkdir build +cd build +export TRIGGERALGS_DIR=$(pwd)/../install # this is for triggermodules to know where this install is. +cmake -DCMAKE_INSTALL_PREFIX=${TRIGGERALGS_DIR} ../ +make -j`nproc` +make install # to move all the insteresting stuff in ${TRIGGERALGS_DIR} +ctest # if you want to run the tests, right now it doesn't do anything interesting +``` + + + +## To contribute +Fork this repo. + + + +## More details on the structs +Note all the times here refer to 50 MHz clock (since epoch), as is now standard in DUNE. + +### TriggerPrimitive +This struct represent hits, it contains: +| Variable | Type | Comment | +|--------------------------|------------|---------------------------------------------------------------------------| +| `time_start` | `int64_t` | Start time | +| `samples_to_peak` | `uint16_t` | Number of samples from the `time_start` to the ADC peak | +| `samples_over_threshold` | `uint16_t` | Number of samples over threshold | +| `channel` | `uint32_t` | Channel number | +| `adc_integral` | `uint16_t` | ADC integral | +| `adc_peak` | `uint16_t` | ADC peak (could be 12 bits, strictly) | +| `detid` | `uint32_t` | detid (a flag that represents the detector which created the TP) | +| `type` | `uint32_t` | some flag that says what it think it is (PDS/TPC for example) | +| `algorithm` | `uint32_t` | some flag that says which algorithm created it (CPU/Firmware for example) | +| `version` | `uint16_t` | version of above | +| `flag` | `uint32_t` | extra flags. | + +### TriggerActivity +Represents a cluster of hits, it contains: +| Variable | Type | Comment | +|-----------------|---------------------------------|-------------------------------------------------------------------------------------------| +| `time_start` | `int64_t` | Start time | +| `time_end` | `int64_t` | End time | +| `time_peak` | `int64_t` | Time where ADC the highest | +| `time_formed` | `int64_t` | Time at which the object was created (maybe we don't need that?) | +| `channel_start` | `uint32_t` | Start channel | +| `channel_end` | `uint32_t` | End channel | +| `channel_peak` | `uint32_t` | Channel of the highest ADC | +| `adc_integral` | `uint16_t` | ADC integral | +| `adc_peak` | `uint16_t` | ADC peak (could be 12 bits, strictly) | +| `detid` | `uint32_t` | detid (a flag that represents the detector in which it ocurred) | +| `type` | `uint32_t` | some flag that says what it think it is (Argon39/Muon for example) | +| `algorithm` | `uint32_t` | some flag that says which algorithm created it (PDS/TPS/SN/high energy/solar for example) | +| `version` | `uint16_t` | version of above | +| `tp_list` | `std::vector` | the list of TPs that was used to create it | + +### TriggerCandidate +contains a trigger "request" (i.e. please trigger). In this case, it's based on activity in the detector, but it could be external trigger as well, if one removes the `ta_list`: +| Variable | Type | Comment | +|----------------|--------------------------------|-----------------------------------------------------------------------------------| +| `time_start` | `int64_t` | Time at which to start the readout | +| `time_end` | `int64_t` | Time at which to end the readout | +| `time_decided` | `int64_t` | Time at which this decision was taken | +| `detid` | `uint32_t` | some flag that represents which part of the detector to readout | +| `type` | `uint32_t` | some flag that says what it think it is (SN/Muon/Beam for example) | +| `algorithm` | `uint32_t` | some flag that says which algorithm created it (SN/high energy/solar for example) | +| `version` | `uint16_t` | version of above | +| `ta_list` | `std::vector` | the list of TAs that was used to create it | + +### TriggerDecision +contains a readout request (i.e. you MUST trigger), based on all the candidates in the detector: +| Variable | Type | Comment | +|------------------|---------------------------------|-------------------------------------------------------------------------------------------------------| +| `time_start` | `int64_t` | Time at which to start the readout | +| `time_end` | `int64_t` | Time at which to end the readout | +| `time_triggered` | `int64_t` | Time at which this decision was taken | +| `detid` | `uint32_t` | some flag that represents which part of the detector to readout | +| `type` | `uint32_t` | some flag that says what it think it is (SN/Muon/Beam for example) | +| `algorithm` | `uint32_t` | some flag that says which algorithm created it (although I think there will only ever be one of this) | +| `version` | `uint16_t` | version of above | +| `tc_list` | `std::vector` | the list of TCs that was used to create it | diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/README.md b/dunetrigger/TriggerSim/triggeralgs/v5/README.md new file mode 100644 index 0000000..ea2f2aa --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/README.md @@ -0,0 +1,3 @@ +# triggeralgs + +This directory is a contains minimally modified source code of the [DUNE-DAQ triggeralgs](https://github.com/DUNE-DAQ/triggeralgs) repository. See README-DUNEDAQ.md for documentation of this repository. diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/autogen/CMakeLists.txt b/dunetrigger/TriggerSim/triggeralgs/v5/autogen/CMakeLists.txt new file mode 100644 index 0000000..b7d06d4 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/autogen/CMakeLists.txt @@ -0,0 +1,28 @@ + +foreach(INC_ALGO ${ALGS_H}) + set_alg_type_name_lib(${INC_ALGO}) + + if ("${ALGONAME}" STREQUAL "") + continue() + endif() + + message(STATUS "Generating auto-compiling file for header " ${INC_ALGO}) + + set(EXECNAME "main_${ALGONAME}") + configure_file(main.cxx.in ${EXECNAME}.cxx "@ONLY") + + add_executable(${EXECNAME} ${EXECNAME}.cxx) + + target_include_directories(${EXECNAME} PUBLIC ${PROJECT_SOURCE_DIR}) + target_include_directories(${EXECNAME} PUBLIC ${PROJECT_SOURCE_DIR}/includes) + + target_link_libraries(${EXECNAME} PUBLIC ${ALGOLIBNAME}) + + target_compile_options(${EXECNAME} PRIVATE + $<$:/W4 /WX> + $<$>:-Wall -Wextra -pedantic -Werror> + ) + + + +endforeach() diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/autogen/main.cxx.in b/dunetrigger/TriggerSim/triggeralgs/v5/autogen/main.cxx.in new file mode 100644 index 0000000..ed3caea --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/autogen/main.cxx.in @@ -0,0 +1,12 @@ +#include "@INC_ALGO@" +#include +#include + +int main() { + std::cout << "@ALGONAME@\n"; + triggeralgs::@ALGONAME@ a; + (void) a; + return 0; +} + + diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/cmake/triggeralgsConfig.cmake.in b/dunetrigger/TriggerSim/triggeralgs/v5/cmake/triggeralgsConfig.cmake.in new file mode 100644 index 0000000..180e9fc --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/cmake/triggeralgsConfig.cmake.in @@ -0,0 +1,30 @@ + +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +# Insert find_dependency() calls for your package's dependencies in +# the place of this comment. Make sure they match up with the +# find_package calls in your package's CMakeLists.txt file + +find_dependency(nlohmann_json) +find_dependency(TRACE) +find_dependency(detdataformats) +find_dependency(trgdataformats) +find_dependency(cetlib) +find_dependency(detchannelmaps) + +if (EXISTS ${CMAKE_SOURCE_DIR}/@PROJECT_NAME@) + +message(STATUS "Project \"@PROJECT_NAME@\" will be treated as repo (found in ${CMAKE_SOURCE_DIR}/@PROJECT_NAME@)") +add_library(@PROJECT_NAME@::@PROJECT_NAME@ ALIAS @PROJECT_NAME@) + +else() + +message(STATUS "Project \"@PROJECT_NAME@\" will be treated as installed package (found in ${CMAKE_CURRENT_LIST_DIR})") +set_and_check(targets_file ${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake) +include(${targets_file}) + +endif() + +check_required_components(@PROJECT_NAME@) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/cmake/triggeralgsConfigVersion.cmake.in b/dunetrigger/TriggerSim/triggeralgs/v5/cmake/triggeralgsConfigVersion.cmake.in new file mode 100644 index 0000000..407e907 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/cmake/triggeralgsConfigVersion.cmake.in @@ -0,0 +1,11 @@ +qset(PACKAGE_VERSION "@TRIGGERALGS_VERSION@") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/exec/CMakeLists.txt b/dunetrigger/TriggerSim/triggeralgs/v5/exec/CMakeLists.txt new file mode 100644 index 0000000..8f637e3 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/exec/CMakeLists.txt @@ -0,0 +1,8 @@ +add_executable(compile_me compile_me.cxx) +add_executable(run_trivial_candidate run_trivial_candidate.cxx) + +target_include_directories(run_trivial_candidate PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(run_trivial_candidate DuneTriggers) +target_link_libraries(run_trivial_candidate ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(compile_me DuneTriggers SupernovaTrigger) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/exec/NaiveTriggerCandidateConsumer.h b/dunetrigger/TriggerSim/triggeralgs/v5/exec/NaiveTriggerCandidateConsumer.h new file mode 100644 index 0000000..3d390ae --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/exec/NaiveTriggerCandidateConsumer.h @@ -0,0 +1,67 @@ +#pragma once + +#include + +#include + +#include "TriggerCandidateMaker.hpp" +/// A simple class that just dumps every candidate it receives in a txt file, and wait random times in between + +class NaiveTriggerCandidateConsumer +{ +protected: + std::ofstream file_out; + std::atomic consume_on; + int n_tc; + NaiveTriggerQueue& tq; + +public: + NaiveTriggerCandidateConsumer(NaiveTriggerQueue& tq_) + : tq(tq_) + , consume_on(false) + , n_tc(0) + { + file_out.open("candidate_dump.csv"); + file_out << "tstart,tend,tpeak,channel_start,channel_end,channel_peak,adc_integral,adc_peak,detid\n"; + } + + void Worker() + { + while (true) { + DuneTriggers::TriggerCandidate tc; + if (tq.GetNextProcessed(tc)) + PrintToFile(tc); + + if (not consume_on.load()) + break; + } + } + + void Start() + { + std::cout << "\033[32mStarting Candidate consumer\033[0m\n"; + consume_on.store(true); + } + + void Stop() + { + std::cout << "\033[32mStopping Candidate consumer\033[0m\n"; + consume_on.store(false); + DuneTriggers::TriggerCandidate tc; + if (tq.tcm.GetLastCluster(tc)) + PrintToFile(tc); + + std::cout << "Created " << n_tc << " TCs.\n"; + } + + void PrintToFile(DuneTriggers::TriggerCandidate& tc) + { + n_tc++; + std::string str = + (std::to_string(tc.time_start) + "," + std::to_string(tc.time_end) + "," + std::to_string(tc.time_peak) + "," + + std::to_string(tc.channel_start) + "," + std::to_string(tc.channel_end) + "," + std::to_string(tc.channel_peak) + + "," + std::to_string(tc.adc_integral) + "," + std::to_string(tc.adc_peak) + "," + std::to_string(tc.detid) + + "\n"); + file_out << str; + } +}; diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/exec/NaiveTriggerQueue.h b/dunetrigger/TriggerSim/triggeralgs/v5/exec/NaiveTriggerQueue.h new file mode 100644 index 0000000..3704d8f --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/exec/NaiveTriggerQueue.h @@ -0,0 +1,121 @@ +#pragma once +#include + +#include "dune-triggers/Trivial/TriggerCandidateMaker_Trivial.hpp" + +class NaiveTriggerQueue +{ +protected: + boost::lockfree::queue queue_in; + boost::lockfree::queue queue_out; + + std::atomic process_on; + + bool bounded_push_with_warning(const DuneTriggers::TriggerPrimitive& dat) + { + if (not queue_in.bounded_push(dat)) { + std::cout << "\033[31mWarning, queue_in is full, not filling!\033[0m\n"; + return false; + } + return true; + } + +public: + DuneTriggers::TriggerCandidateMaker& tcm; + NaiveTriggerQueue(DuneTriggers::TriggerCandidateMaker& tcm_, size_t depth_in = 100, size_t depth_out = 100) + : queue_in(depth_in) + , queue_out(depth_out) + , process_on(false) + , tcm(tcm_) + { + assert(queue_in.is_lock_free()); + assert(queue_out.is_lock_free()); + } + + void AddToQueue(const DuneTriggers::TriggerPrimitive& dat) { bounded_push_with_warning(dat); } + + void AddToQueue(const std::vector& dats) + { + std::for_each(dats.begin(), dats.end(), [this](const DuneTriggers::TriggerPrimitive dat) -> void { + this->bounded_push_with_warning(dat); + }); + } + + void Worker() + { + while (true) { + + DuneTriggers::TriggerPrimitive tp; + std::vector tcs; + + if (queue_in.pop(tp)) + tcm(tp, tcs); + + for (auto const& tc : tcs) { + queue_out.push(tc); + } + + if (not process_on.load()) + break; + } + } + + void Start() { process_on.store(true); } + + void Stop() { process_on.store(false); } + + void SoftStop() + { + + // // Nothing will be sending data anymore + // mtx_queue_in.lock(); + + // if (not queue_in.empty()) { + // std::cout << "TPs queue not entirely consumed, doing that now.\n"; + // DuneTriggers::TriggerPrimitive tp; + + // while (get_next_in_queue_no_mutex(tp)) { + + // std::vector tcs; + // tcm(tp,tcs); + // mtx_queue_out.lock(); + + // for (auto const& tc: tcs) { + // queue_out.push_back(tc); + // } + // mtx_queue_out.unlock(); + // } + // std::cout << "TPs consumed\n"; + // } + + // mtx_queue_in.unlock(); // Doesn't matter anyway + + int n_tries = 10, i_try = 0; + + while (true) { + + bool should_try_again = (not queue_out.empty() and i_try < n_tries); + + if (!should_try_again) + break; + + if (not i_try) { + std::cout << "TC queue isn't empty, waiting for consumer"; + } else { + std::cout << "."; + } + + std::chrono::milliseconds millisec_wait(50); + std::this_thread::sleep_for(millisec_wait); + i_try++; + } + std::cout << "\n"; + if (not queue_out.empty()) { + std::cout << "The consumer of TC hasn't caught up\n"; + } + + process_on.store(false); + } + + const bool GetNextProcessed(DuneTriggers::TriggerCandidate& dat) { return queue_out.pop(dat); } +}; diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/exec/compile_me.cxx b/dunetrigger/TriggerSim/triggeralgs/v5/exec/compile_me.cxx new file mode 100644 index 0000000..f62be46 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/exec/compile_me.cxx @@ -0,0 +1,28 @@ +/** + * @file compile_me.cxx + * + * TODO: Eric Flumerfelt May-21-2021: Please explain what this file is for + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dune-triggers/Supernova/TriggerCandidateMaker_Supernova.hpp" +#include "dune-triggers/Trivial/TriggerCandidateMaker_Trivial.hpp" +#include "dune-triggers/Trivial/TriggerDecisionMaker_Trivial.hpp" +#include + +int +main() +{ + std::string s; + TriggerCandidateMakerTrivial trivial(s); + (void)trivial; + TriggerDecisionMakerTrivial trivial2(s); + (void)trivial2; + TriggerCandidateMakerSupernova super(s); + (void)super; + + return 0; +} diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/exec/run_trivial_candidate.cxx b/dunetrigger/TriggerSim/triggeralgs/v5/exec/run_trivial_candidate.cxx new file mode 100644 index 0000000..e25c8df --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/exec/run_trivial_candidate.cxx @@ -0,0 +1,124 @@ +/** + * @file run_trivial_candidate.cxx + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "NaiveTriggerCandidateConsumer.h" +#include "NaiveTriggerQueue.h" + +#include "logging/Logging.hpp" + +#include "dune-triggers/Trivial/TriggerCandidateMaker_Trivial.hpp" + +#include + +#include +#include +#include +#include +#include + +using namespace DuneTriggers; + +using pd_clock = std::chrono::duration>; + +std::default_random_engine generator; + +std::uniform_int_distribution rdm_channel(0, 2560); +std::normal_distribution rdm_adc(20, 5); +std::normal_distribution rdm_time_over_threshold(100, 20); // nanosec +std::normal_distribution rdm_start_time(0, 20); // nanosec +std::uniform_real_distribution rdm_peak_time(0, 1); + +auto time_ref = + std::chrono::steady_clock::now(); // a time reference such that numbers aren't so big (start of DUNE time?) + +TriggerPrimitive +GetRandomTP(std::chrono::time_point& now) +{ + TriggerPrimitive tp; + + double start = rdm_start_time(generator); + double tot = rdm_time_over_threshold(generator); + double peak = rdm_peak_time(generator) * tot; + + std::chrono::nanoseconds tot_time(static_cast(tot)); + std::chrono::nanoseconds peak_time(static_cast(peak)); + std::chrono::nanoseconds start_time(static_cast(start)); + + auto tp_start_time = now - time_ref + start_time; + + tp.time_start = pd_clock(tp_start_time).count(); + tp.samples_over_threshold = pd_clock(tot_time).count(); // FIXME: Variable names are confusing. Moving on since this is a test app. + tp.samples_to_peak = pd_clock(peak_time).count(); + tp.channel = rdm_channel(generator); + tp.adc_integral = rdm_adc(generator); + tp.adc_peak = rdm_adc(generator); + tp.detid = tp.channel; + + return tp; +} + +int +main() +{ + generator.seed(std::chrono::system_clock::now().time_since_epoch().count()); + int n_second_generating = 2; + // millisec or kHz + std::exponential_distribution tp_rate(3); + std::normal_distribution n_tp(20, 2); + std::normal_distribution electronic_delay(0, 0); + + TriggerCandidateMakerTrivial tcmt(""); + NaiveTriggerQueue tq(tcmt); + NaiveTriggerCandidateConsumer tcc(tq); + + tq.Start(); + tcc.Start(); + std::thread worker_thread(&NaiveTriggerQueue::Worker, &tq); + std::thread consumer_thread(&NaiveTriggerCandidateConsumer::Worker, &tcc); + int n_tps_total = 0; + int n_cluster = 0; + + std::chrono::time_point start_time = std::chrono::steady_clock::now(); + while (true) { + auto now = std::chrono::steady_clock::now(); + int n = n_tp(generator); + n_tps_total += n; + std::vector tps; + n_cluster += n > 0; + + for (int i = 0; i < n; ++i) { + tps.push_back(GetRandomTP(now)); + } + + uint64_t wait = electronic_delay(generator); // NOLINT(build/unsigned) + std::chrono::milliseconds millisec_wait(wait); + std::this_thread::sleep_for(millisec_wait); + + tq.AddToQueue(tps); + + wait = tp_rate(generator); + millisec_wait = std::chrono::milliseconds(wait); + std::this_thread::sleep_for(millisec_wait); + + if (now - start_time > std::chrono::seconds(n_second_generating)) { + break; + } + } + std::chrono::time_point end_time = std::chrono::steady_clock::now(); + + TLOG() << "TPs created: " << n_tps_total; + TLOG() << "\"True\" clusters created: " << n_cluster; + auto dt = std::chrono::duration_cast(end_time - start_time); + TLOG() << "Average TP rate: " << n_tps_total / static_cast(dt.count()) * 1000000. << " MHz"; + + tq.SoftStop(); + tcc.Stop(); + + worker_thread.join(); + consumer_thread.join(); +} diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/CMakeLists.txt b/dunetrigger/TriggerSim/triggeralgs/v5/include/CMakeLists.txt new file mode 100644 index 0000000..79a4693 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(triggeralgs) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/AlgorithmFlowChart.png b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/AlgorithmFlowChart.png new file mode 100644 index 0000000000000000000000000000000000000000..b1001ee53cf1108cd11094de2accbae66b2d3b1c GIT binary patch literal 80185 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󯸞r1Cbs)TxBFRlyx4XAEZ- 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ξ~_J&Prc#%MZ`h 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 literal 0 HcmV?d00001 diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/README.md b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/README.md new file mode 100644 index 0000000..99ba57e --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/README.md @@ -0,0 +1,32 @@ +# ADCSimpleWindow + + - A “next-to-most-simple” triggering algorithm to exercise the TP chain. + - Look at the total ADC of incoming TPs in a given time window (`window_length`), trigger if that total goes above some user defined threshold (`adc_threshold`). Both `window_length` and `adc_threshold` are configurable members of the `TAMakerADCSimpleWindow` class. Defaults obtained based on the data in `tps_link_11.txt`. + - All of the logic is implemented in the `TAMakerADCSimpleWindow` class. A nested class called `Window` monitors incoming TPs (which are time ordered). + - When a particular window exceeds threshold, `TAMakerADCSimpleWindow::construct_ta()` constructs a `TriggerActivity`. This is enough (eventually) to request data to be read out. The `TCMakerADCSimpleWindowAlgorithm` class simply constructs trigger candidates one-for-one from the trigger activities. + - Note that an activity will only be constructed once the window is full length even if the total ADC goes above the threshold beforehand. For example, if the user defines a window 1 ms in length and the ADC threshold is reached after 0.5 ms, a candidate will only be constructed once a TP is received with a start time 1 ms after the first TP in that window. + - Can use `faketp_chain` confgen to generate the configuration to run the fake TP chain with the `ADCSimpleWindow` algorithm: + ``` +python -m trigger.faketp_chain -a TAMakerADCSimpleWindowPlugin -A "dict(window_length=100000,adc_threshold=1000000)" -c TCMakerADCSimpleWindowPlugin -f tps_link_11.txt faketp_chain_ADCSimpleWindow +``` + - Then to run: +``` +python -m nanorc config_dir boot init conf start 1 resume wait 60 stop +``` + + +## `Window`: `TAMakerADCSimpleWindow` Nested Class: + - Most of the logic is dealt with by the `Window` class, a class nested inside `TAMakerADCSimpleWindow`. + - It contains three member functions and five functions. `operator<<` is also defined. The following explanations can be used to interpret the accompanying flow chart. + - `time_start`: Start time of the first TP chronologically in the window. + - `adc_integral`: Total ADC of the TPs in the window. + - `tp_list`: A vector of TPs in the window. + - `is_empty()`: If the vector of TPs is empty, returns true, else false. + - `clear()`: Clears the vector of TPs. + - `move()`: Find all of the TPs in the current window which need to be removed if the input TP is to be added and the earliest and latest TPs in the window aren’t separated by more than `window_length`. The earliest TPs in the window are removed (their ADC contribution subtracted) until this condition is satisfied. `time_start` for the window is then set to what is now the first TP start time. Note that in the case that the input TP is further away than 1 `window_length` from the latest TP in the window, the window is reset with the input TP. + - `reset():` Clear the TP list, restart the ADC sum, set the start time of the window to the start time of the input TP. Add, the input TP to the window TP list. + - `add()`: Add input TP to window TP list and its ADC to window ADC total. + +

+ +

diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/TAMakerADCSimpleWindowAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/TAMakerADCSimpleWindowAlgorithm.hpp new file mode 100644 index 0000000..fa9e575 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/TAMakerADCSimpleWindowAlgorithm.hpp @@ -0,0 +1,100 @@ +/** + * @file TAMakerADCSimpleWindowAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_ADCSIMPLEWINDOW_TRIGGERACTIVITYMAKERADCSIMPLEWINDOW_HPP_ +#define TRIGGERALGS_ADCSIMPLEWINDOW_TRIGGERACTIVITYMAKERADCSIMPLEWINDOW_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp" + +#include + +namespace triggeralgs { +class TAMakerADCSimpleWindowAlgorithm : public TriggerActivityMaker +{ + +public: + void process(const TriggerPrimitive& input_tp, std::vector& output_ta); + + void configure(const nlohmann::json &config); + +private: + class Window { + public: + bool is_empty() const{ + return tp_list.empty(); + }; + void add(TriggerPrimitive const &input_tp){ + // Add the input TP's contribution to the total ADC and add it to + // the TP list. + adc_integral += input_tp.adc_integral; + tp_list.push_back(input_tp); + }; + void clear(){ + tp_list.clear(); + }; + void move(TriggerPrimitive const &input_tp, timestamp_t const &window_length){ + // Find all of the TPs in the window that need to be removed + // if the input_tp is to be added and the size of the window + // is to be conserved. + // Substract those TPs' contribution from the total window ADC. + uint32_t n_tps_to_erase = 0; + for(auto tp : tp_list){ + if(!(input_tp.time_start-tp.time_start < window_length)){ + n_tps_to_erase++; + adc_integral -= tp.adc_integral; + } + else break; + } + // Erase the TPs from the window. + tp_list.erase(tp_list.begin(), tp_list.begin()+n_tps_to_erase); + // Make the window start time the start time of what is now the + // first TP. + if(tp_list.size()!=0){ + time_start = tp_list.front().time_start; + add(input_tp); + } + else reset(input_tp); + }; + void reset(TriggerPrimitive const &input_tp){ + // Empty the TP list. + tp_list.clear(); + // Set the start time of the window to be the start time of the + // input_tp. + time_start = input_tp.time_start; + // Start the total ADC integral. + adc_integral = input_tp.adc_integral; + // Add the input TP to the TP list. + tp_list.push_back(input_tp); + }; + friend std::ostream& operator<<(std::ostream& os, const Window& window){ + if(window.is_empty()) os << "Window is empty!\n"; + else{ + os << "Window start: " << window.time_start << ", end: " << window.tp_list.back().time_start; + os << ". Total of: " << window.adc_integral << " ADC counts with " << window.tp_list.size() << " TPs.\n"; + } + return os; + }; + + timestamp_t time_start; + uint32_t adc_integral; + std::vector tp_list; + }; + + TriggerActivity construct_ta() const; + + Window m_current_window; + uint64_t m_primitive_count = 0; + + // Configurable parameters. + uint32_t m_adc_threshold = 1200000; + timestamp_t m_window_length = 100000; +}; +} // namespace triggeralgs + +#endif // TRIGGERALGS_ADCSIMPLEWINDOW_TRIGGERACTIVITYMAKERADCSIMPLEWINDOW_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/TCMakerADCSimpleWindowAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/TCMakerADCSimpleWindowAlgorithm.hpp new file mode 100644 index 0000000..1a5ec23 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/TCMakerADCSimpleWindowAlgorithm.hpp @@ -0,0 +1,34 @@ +/** + * @file TCMakerADCSimpleWindowAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_ADCSIMPLEWINDOW_TRIGGERCANDIDATEMAKERADCSIMPLEWINDOW_HPP_ +#define TRIGGERALGS_ADCSIMPLEWINDOW_TRIGGERCANDIDATEMAKERADCSIMPLEWINDOW_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" + +#include + +namespace triggeralgs { +class TCMakerADCSimpleWindowAlgorithm : public TriggerCandidateMaker +{ + +public: + /// The function that gets call when there is a new activity + void process(const TriggerActivity&, std::vector&); + + void configure(const nlohmann::json &config); + +private: + + uint64_t m_activity_count = 0; // NOLINT(build/unsigned) + +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_ADCSIMPLEWINDOW_TRIGGERCANDIDATEMAKERADCSIMPLEWINDOW_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hpp new file mode 100644 index 0000000..ffe4ab6 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hpp @@ -0,0 +1,49 @@ +/* @file: AbstractFactory.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2023. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_ABSTRACT_FACTORY_HPP_ +#define TRIGGERALGS_ABSTRACT_FACTORY_HPP_ + +// #include "logging/Logging.hpp" + +#include +#include +#include +#include + +namespace triggeralgs { + +template +class AbstractFactory +{ + using maker_creator = std::function()>; + using creation_map = std::unordered_map; + + public: + AbstractFactory() {} + AbstractFactory(const AbstractFactory&) = delete; + AbstractFactory& operator=(const AbstractFactory&) = delete; + virtual ~AbstractFactory() {} + + std::unique_ptr build_maker(const std::string& alg_name); + + static void register_creator(const std::string alg_name, maker_creator creator); + + static std::shared_ptr> get_instance(); + + protected: + static std::shared_ptr> s_single_factory; + + private: + static creation_map& get_makers(); +}; + +} /* namespace triggeralgs */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hxx" + +#endif // TRIGGERALGS_ABSTRACT_FACTORY_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hxx b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hxx new file mode 100644 index 0000000..7720acb --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hxx @@ -0,0 +1,64 @@ +/* @file: AbstractFactory.hxx + * + * This is part of the DUNE DAQ Application Framework, copyright 2023. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_ABSTRACT_FACTORY_HXX_ +#define TRIGGERALGS_ABSTRACT_FACTORY_HXX_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Issues.hpp" + +namespace triggeralgs { + +template +std::shared_ptr> AbstractFactory::s_single_factory = nullptr; + +template +typename AbstractFactory::creation_map& AbstractFactory::get_makers(){ + static creation_map s_makers; + return s_makers; +} + +template +void AbstractFactory::register_creator(const std::string alg_name, maker_creator creator) +{ + creation_map& makers = get_makers(); + auto it = makers.find(alg_name); + + if (it == makers.end()) { + makers[alg_name] = creator; + return; + } +// throw FactoryOverwrite(ERS_HERE, alg_name); + return; +} + +template +std::unique_ptr AbstractFactory::build_maker(const std::string& alg_name) +{ + creation_map& makers = get_makers(); + auto it = makers.find(alg_name); + + if (it != makers.end()) { +// TLOG() << "[AF] Factory building " << alg_name << "."; + return it->second(); + } + +// throw FactoryNotFound(ERS_HERE, alg_name); + return nullptr; +} + +template +std::shared_ptr> AbstractFactory::get_instance() +{ + if (s_single_factory == nullptr) { + s_single_factory = std::make_shared>(); + } + return s_single_factory; +} + +} // namespace triggeralgs + +#endif // TRIGGERALGS_ABSTRACT_FACTORY_HXX_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/BundleN/TAMakerBundleNAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/BundleN/TAMakerBundleNAlgorithm.hpp new file mode 100644 index 0000000..465574c --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/BundleN/TAMakerBundleNAlgorithm.hpp @@ -0,0 +1,33 @@ +/** + * @file TAMakerBundleNAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_BUNDLEN_TRIGGERACTIVITYMAKERBUNDLEN_HPP_ +#define TRIGGERALGS_BUNDLEN_TRIGGERACTIVITYMAKERBUNDLEN_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" + +#include + +namespace triggeralgs { + +class TAMakerBundleNAlgorithm : public TriggerActivityMaker +{ + public: + void process(const TriggerPrimitive& input_tp, std::vector& output_tas); + void configure(const nlohmann::json& config); + bool bundle_condition(); + + private: + uint64_t m_bundle_size = 1; + TriggerActivity m_current_ta; + void set_ta_attributes(); +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_BUNDLEN_TRIGGERACTIVITYMAKERBUNDLEN_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/BundleN/TCMakerBundleNAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/BundleN/TCMakerBundleNAlgorithm.hpp new file mode 100644 index 0000000..9571587 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/BundleN/TCMakerBundleNAlgorithm.hpp @@ -0,0 +1,33 @@ +/** + * @file TCMakerBundleNAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_BUNDLEN_TRIGGERCANDIDATEMAKERBUNDLEN_HPP_ +#define TRIGGERALGS_BUNDLEN_TRIGGERCANDIDATEMAKERBUNDLEN_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" + +#include + +namespace triggeralgs { + +class TCMakerBundleNAlgorithm: public TriggerCandidateMaker +{ + public: + void process(const TriggerActivity& input_ta, std::vector& output_tcs); + void configure(const nlohmann::json& config); + bool bundle_condition(); + + private: + uint64_t m_bundle_size = 1; + TriggerCandidate m_current_tc; + void set_tc_attributes(); +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_BUNDLEN_TRIGGERCANDIDATEMAKERBUNDLEN_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/README.md b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/README.md new file mode 100644 index 0000000..72075a2 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/README.md @@ -0,0 +1,3 @@ +The ChannelAdjacency algorithm is a refined version of the HorizontalMuon algorithm (only the TA maker part for the moment). TA logic changes: in a given TP window (of default 8000 ticks), when TAs are constructed, they only contain the TPs which form an activity/track (and are not the outliers). More than one TAs per window are allowed but they should not be overlapping! + +More details can be found here https://indico.fnal.gov/event/63863/ (Horizontal Muon refinement by SS Chhibra) \ No newline at end of file diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/TAMakerChannelAdjacencyAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/TAMakerChannelAdjacencyAlgorithm.hpp new file mode 100644 index 0000000..85d4f74 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/TAMakerChannelAdjacencyAlgorithm.hpp @@ -0,0 +1,42 @@ +/** + * @file TAMakerChannelAdjacencyAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_CHANNELADJACENCY_TRIGGERACTIVITYMAKERCHANNELADJACENCY_HPP_ +#define TRIGGERALGS_CHANNELADJACENCY_TRIGGERACTIVITYMAKERCHANNELADJACENCY_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TPWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" +#include +#include + +namespace triggeralgs { +class TAMakerChannelAdjacencyAlgorithm : public TriggerActivityMaker +{ +public: + void process(const TriggerPrimitive& input_tp, std::vector& output_ta); + void configure(const nlohmann::json& config); + +private: + TriggerActivity construct_ta(TPWindow) const; + + TPWindow check_adjacency(); + + TPWindow m_current_window; + + // Configurable parameters. + bool m_print_tp_info = false; // Prints out some information on every TP received + uint16_t m_adjacency_threshold = 15; // Default is 15 wire track for testing + uint16_t m_adj_tolerance = 3; // Adjacency tolerance - default is 3 from coldbox testing. + timestamp_t m_window_length = 8000; // Shouldn't exceed the max drift which is ~9375 62.5 MHz ticks for VDCB + + // For debugging and performance study purposes. + void add_window_to_record(TPWindow window); + std::vector m_window_record; +}; +} // namespace triggeralgs +#endif // TRIGGERALGS_CHANNELADJACENCY_TRIGGERACTIVITYMAKERCHANNELADJACENCY_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/TCMakerChannelAdjacencyAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/TCMakerChannelAdjacencyAlgorithm.hpp new file mode 100644 index 0000000..badecb3 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/TCMakerChannelAdjacencyAlgorithm.hpp @@ -0,0 +1,46 @@ +/** + * @file TCMakerChannelAdjacencyAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_CHANNELADJACENCY_TRIGGERCANDIDATEMAKERCHANNELADJACENCY_HPP_ +#define TRIGGERALGS_CHANNELADJACENCY_TRIGGERCANDIDATEMAKERCHANNELADJACENCY_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TAWindow.hpp" + +#include +#include + +namespace triggeralgs { +class TCMakerChannelAdjacencyAlgorithm : public TriggerCandidateMaker +{ + +public: + // The function that gets called when there is a new activity + void process(const TriggerActivity&, std::vector&); + void configure(const nlohmann::json& config); + +private: + + TriggerCandidate construct_tc() const; + + TAWindow m_current_window; + uint64_t m_activity_count = 0; // NOLINT(build/unsigned) + + // Configurable parameters. + bool m_trigger_on_adc = false; + bool m_trigger_on_n_channels = false; + uint32_t m_adc_threshold = 1200000; + uint16_t m_n_channels_threshold = 600; // 80ish for frames, O(200 - 600) for tpslink + timestamp_t m_window_length = 80000; + + // For debugging purposes. + void add_window_to_record(TAWindow window); + std::vector m_window_record; +}; +} // namespace triggeralgs +#endif // TRIGGERALGS_CHANNELADJACENCY_TRIGGERCANDIDATEMAKERCHANNELADJACENCY_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelDistance/TAMakerChannelDistanceAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelDistance/TAMakerChannelDistanceAlgorithm.hpp new file mode 100644 index 0000000..be7253e --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelDistance/TAMakerChannelDistanceAlgorithm.hpp @@ -0,0 +1,35 @@ +/** + * @file TAMakerChannelDistanceAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_CHANNELDISTANCE_TRIGGERACTIVITYMAKERCHANNELDISTANCE_HPP_ +#define TRIGGERALGS_CHANNELDISTANCE_TRIGGERACTIVITYMAKERCHANNELDISTANCE_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" +#include + +namespace triggeralgs { + +class TAMakerChannelDistanceAlgorithm : public TriggerActivityMaker { + public: + void process(const TriggerPrimitive& input_tp, std::vector& output_tas); + void configure(const nlohmann::json& config); + void set_ta_attributes(); + + private: + void set_new_ta(const TriggerPrimitive& input_tp); + TriggerActivity m_current_ta; + uint32_t m_max_channel_distance = 50; + uint64_t m_window_length = 8000; + uint16_t m_min_tps = 20; // AEO: Type is arbitrary. Surprised even asking for 2^8 TPs. + uint32_t m_current_lower_bound; + uint32_t m_current_upper_bound; +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_CHANNELDISTANCE_TRIGGERACTIVITYMAKERCHANNELDISTANCE_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelDistance/TCMakerChannelDistanceAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelDistance/TCMakerChannelDistanceAlgorithm.hpp new file mode 100644 index 0000000..8ceb9ae --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelDistance/TCMakerChannelDistanceAlgorithm.hpp @@ -0,0 +1,32 @@ +/** + * @file TCMakerChannelDistanceAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_CHANNELDISTANCE_TRIGGERCANDIDATEMAKERCHANNELDISTANCE_HPP_ +#define TRIGGERALGS_CHANNELDISTANCE_TRIGGERCANDIDATEMAKERCHANNELDISTANCE_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" +#include + +namespace triggeralgs { + +class TCMakerChannelDistanceAlgorithm : public TriggerCandidateMaker { + public: + void process(const TriggerActivity& input_ta, std::vector& output_tcs); + void configure(const nlohmann::json& config); + void set_tc_attributes(); + + private: + void set_new_tc(const TriggerActivity& input_ta); + TriggerCandidate m_current_tc; + uint16_t m_current_tp_count; + uint16_t m_max_tp_count = 1000; // Produce a TC when this count is exceeded. AEO: Arbitrary choice of 1000. +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_CHANNELDISTANCE_TRIGGERCANDIDATEMAKERCHANNELDISTANCE_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/README.md b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/README.md new file mode 100644 index 0000000..68a60ee --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/README.md @@ -0,0 +1,4 @@ +# HorizontalMuon + + - Coming soon. For now please see https://indico.fnal.gov/event/51502/contributions/226506/attachments/148509/190809/211019_FDDS_HorizontalMuon.pdf + diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/TAMakerHorizontalMuonAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/TAMakerHorizontalMuonAlgorithm.hpp new file mode 100644 index 0000000..6538246 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/TAMakerHorizontalMuonAlgorithm.hpp @@ -0,0 +1,55 @@ +/** + * @file TAMakerHorizontalMuonAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_HORIZONTALMUON_TRIGGERACTIVITYMAKERHORIZONTALMUON_HPP_ +#define TRIGGERALGS_HORIZONTALMUON_TRIGGERACTIVITYMAKERHORIZONTALMUON_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TPWindow.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" +#include +#include + +namespace triggeralgs { +class TAMakerHorizontalMuonAlgorithm : public TriggerActivityMaker +{ +public: + void process(const TriggerPrimitive& input_tp, std::vector& output_ta); + void configure(const nlohmann::json& config); + +private: + TriggerActivity construct_ta() const; + uint16_t check_adjacency() const; // Returns longest string of adjacent collection hits in window + + TPWindow m_current_window; // Holds collection hits only + int check_sot() const; + + // Configurable parameters. + bool m_trigger_on_adc = false; + bool m_trigger_on_n_channels = false; + bool m_trigger_on_adjacency = true; // Default use of the horizontal muon triggering + bool m_trigger_on_sot = false; + uint16_t m_sot_threshold = 5000; // Time over threshold - threshold to exceed. + bool m_print_tp_info = false; // Prints out some information on every TP received + uint16_t m_adjacency_threshold = 15; // Default is 15 wire track for testing + int m_max_adjacency = 0; // The maximum adjacency seen so far in any window + uint32_t m_adc_threshold = 3000000; // Not currently triggering on this + uint16_t m_n_channels_threshold = 400; // Set this to ~80 for frames.bin, ~150-300 for tps_link_11.txt + uint16_t m_adj_tolerance = 3; // Adjacency tolerance - default is 3 from coldbox testing. + int index = 0; + uint16_t ta_adc = 0; + uint16_t ta_channels = 0; + timestamp_t m_window_length = 8000; // Shouldn't exceed the max drift which is ~9375 62.5 MHz ticks for VDCB + + // For debugging and performance study purposes. + void add_window_to_record(TPWindow window); + void dump_window_record(); + void dump_tp(TriggerPrimitive const& input_tp); + std::vector m_window_record; +}; +} // namespace triggeralgs +#endif // TRIGGERALGS_HORIZONTALMUON_TRIGGERACTIVITYMAKERHORIZONTALMUON_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/TCMakerHorizontalMuonAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/TCMakerHorizontalMuonAlgorithm.hpp new file mode 100644 index 0000000..8bf76ec --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/TCMakerHorizontalMuonAlgorithm.hpp @@ -0,0 +1,49 @@ +/** + * @file TCMakerHorizontalMuonAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_HORIZONTALMUON_TRIGGERCANDIDATEMAKERHORIZONTALMUON_HPP_ +#define TRIGGERALGS_HORIZONTALMUON_TRIGGERCANDIDATEMAKERHORIZONTALMUON_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TAWindow.hpp" + +#include +#include + +namespace triggeralgs { +class TCMakerHorizontalMuonAlgorithm : public TriggerCandidateMaker +{ + +public: + // The function that gets called when there is a new activity + void process(const TriggerActivity&, std::vector&); + void configure(const nlohmann::json& config); + +private: + + TriggerCandidate construct_tc() const; + bool check_adjacency() const; + + TAWindow m_current_window; + uint64_t m_activity_count = 0; // NOLINT(build/unsigned) + + // Configurable parameters. + bool m_trigger_on_adc = false; + bool m_trigger_on_n_channels = false; + uint32_t m_adc_threshold = 1200000; + uint16_t m_n_channels_threshold = 600; // 80ish for frames, O(200 - 600) for tpslink + timestamp_t m_window_length = 80000; + int tc_number = 0; + + // For debugging purposes. + void add_window_to_record(TAWindow window); + void dump_window_record(); + std::vector m_window_record; +}; +} // namespace triggeralgs +#endif // TRIGGERALGS_HORIZONTALMUON_TRIGGERCANDIDATEMAKERHORIZONTALMUON_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Issues.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Issues.hpp new file mode 100644 index 0000000..6e3b7e1 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Issues.hpp @@ -0,0 +1,38 @@ +/** +* @file Issues.hpp +* +* This is part of the DUNE DAQ Application Framework, copyright 2020. +* Licensing/copyright details are in the COPYING file that you should have +* received with this code. +*/ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_ISSUES_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_ISSUES_HPP_ + +// #include "ers/Issue.hpp" +// #include "logging/Logging.hpp" // NOTE: if ISSUES ARE DECLARED BEFORE include logging/Logging.hpp, TLOG_DEBUG< + +// ERS_DECLARE_ISSUE(triggeralgs, +// FactoryOverwrite, +// "Attempted to overwrite a creator in factory with " << alg_name, +// ((std::string)alg_name)) + +// ERS_DECLARE_ISSUE(triggeralgs, +// FactoryNotFound, +// "Factory couldn't find: " << alg_name, +// ((std::string)alg_name)) + +// ERS_DECLARE_ISSUE(triggeralgs, +// BadConfiguration, +// "Bad configuration in " << alg_name, +// ((std::string)alg_name)) + +// ERS_DECLARE_ISSUE(triggeralgs, +// InvalidConfiguration, +// "Invalid configuration error: " << conferror, +// ((std::string)conferror)) + + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_ISSUES_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Logging.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Logging.hpp new file mode 100644 index 0000000..c9c273f --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Logging.hpp @@ -0,0 +1,30 @@ +/** + * @file Logging.hpp Common logging declarations in triggeralgs + * + * This is part of the DUNE DAQ , copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ +#ifndef TRIGGERALGS_INCLUDE_LOGGING_HPP_ +#define TRIGGERALGS_INCLUDE_LOGGING_HPP_ + +namespace triggeralgs { + +/** +* @brief Common name used by TRACE TLOG calls from this package +*/ +enum Logging +{ + TLVL_VERY_IMPORTANT = 1, + TLVL_IMPORTANT = 2, + TLVL_GENERAL = 3, + TLVL_DEBUG_INFO = 4, + TLVL_DEBUG_LOW = 5, + TLVL_DEBUG_MEDIUM = 10, + TLVL_DEBUG_HIGH = 15, + TLVL_DEBUG_ALL = 20 +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_LOGGING_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/README.md b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/README.md new file mode 100644 index 0000000..68a60ee --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/README.md @@ -0,0 +1,4 @@ +# HorizontalMuon + + - Coming soon. For now please see https://indico.fnal.gov/event/51502/contributions/226506/attachments/148509/190809/211019_FDDS_HorizontalMuon.pdf + diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/TAMakerMichelElectronAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/TAMakerMichelElectronAlgorithm.hpp new file mode 100644 index 0000000..d679cfe --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/TAMakerMichelElectronAlgorithm.hpp @@ -0,0 +1,133 @@ +/** + * @file TAMakerMichelElectronAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_MICHELELECTRON_TRIGGERACTIVITYMAKERMICHELELECTRON_HPP_ +#define TRIGGERALGS_MICHELELECTRON_TRIGGERACTIVITYMAKERMICHELELECTRON_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" +#include +#include + +namespace triggeralgs { +class TAMakerMichelElectronAlgorithm : public TriggerActivityMaker +{ + +public: + void process(const TriggerPrimitive& input_tp, std::vector& output_ta); + + void configure(const nlohmann::json& config); + +private: + class Window + { + public: + bool is_empty() const { return inputs.empty(); }; + void add(TriggerPrimitive const& input_tp) + { + // Add the input TP's contribution to the total ADC, increase hit channel's hit count and add it to the TP list. + adc_integral += input_tp.adc_integral; + channel_states[input_tp.channel]++; + inputs.push_back(input_tp); + }; + void clear() { inputs.clear(); }; + uint16_t n_channels_hit() { return channel_states.size(); }; + void move(TriggerPrimitive const& input_tp, timestamp_t const& window_length) + { + // Find all of the TPs in the window that need to be removed + // if the input_tp is to be added and the size of the window + // is to be conserved. + // Substract those TPs' contribution from the total window ADC and remove their + // contributions to the hit counts. + uint32_t n_tps_to_erase = 0; + for (auto tp : inputs) { + if (!(input_tp.time_start - tp.time_start < window_length)) { + n_tps_to_erase++; + adc_integral -= tp.adc_integral; + channel_states[tp.channel]--; + // If a TP being removed from the window results in a channel no longer having + // any hits, remove from the states map so map.size() can be used for number + // channels hit. + if (channel_states[tp.channel] == 0) + channel_states.erase(tp.channel); + } else + break; + } + // Erase the TPs from the window. + inputs.erase(inputs.begin(), inputs.begin() + n_tps_to_erase); + // Make the window start time the start time of what is now the first TP. + + if (!(inputs.size() == 0)) { + time_start = inputs.front().time_start; + add(input_tp); + } else { + // std::cout << "Resetting window." << std::endl; + reset(input_tp); + } + }; + void reset(TriggerPrimitive const& input_tp) + { + + // Empty the channel and TP lists. + channel_states.clear(); + inputs.clear(); + // Set the start time of the window to be the start time of theinput_tp. + time_start = input_tp.time_start; + // Start the total ADC integral. + adc_integral = input_tp.adc_integral; + // Start hit count for the hit channel. + channel_states[input_tp.channel]++; + // Add the input TP to the TP list. + inputs.push_back(input_tp); + // std::cout << "Number of channels hit: " << n_channels_hit() << std::endl; + }; + friend std::ostream& operator<<(std::ostream& os, const Window& window) + { + if (window.is_empty()) + os << "Window is empty!\n"; + else { + os << "Window start: " << window.time_start << ", end: " << window.inputs.back().time_start; + os << ". Total of: " << window.adc_integral << " ADC counts with " << window.inputs.size() << " TPs.\n"; + os << window.channel_states.size() << " independent channels have hits.\n"; + } + return os; + }; + + timestamp_t time_start; + uint32_t adc_integral; + std::unordered_map channel_states; + std::vector inputs; + }; + + TriggerActivity construct_ta() const; + std::vector longest_activity() const; + bool check_bragg_peak(std::vector trackHits); + bool check_kinks(std::vector trackHits); + + Window m_current_window; + uint64_t m_primitive_count = 0; + + // Configurable parameters. + // triggeractivitymakerhorizontalmuon::ConfParams m_conf; + bool debug = false; // Use to control whether functions write out useful info + uint16_t m_adjacency_threshold = 15; // Default is 15 for trigger + int m_max_adjacency = 0; // The maximum adjacency seen so far in any window + uint16_t m_adj_tolerance = 3; // Adjacency tolerance - default is 3 from coldbox testing. + int index = 0; + uint16_t ta_adc = 0; + uint16_t ta_channels = 0; + timestamp_t m_window_length = 50000; + + // For debugging purposes. + void add_window_to_record(Window window); + void dump_window_record(); + void dump_tp(TriggerPrimitive const& input_tp); + std::vector m_window_record; +}; +} // namespace triggeralgs + +#endif // TRIGGERALGS_MICHELELECTRON_TRIGGERACTIVITYMAKERMICHELELECTRON_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/TCMakerMichelElectronAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/TCMakerMichelElectronAlgorithm.hpp new file mode 100644 index 0000000..4d6902b --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/TCMakerMichelElectronAlgorithm.hpp @@ -0,0 +1,152 @@ +/** + * @file TCMakerMichelElectronAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_MICHELELECTRON_TRIGGERCANDIDATEMAKERMICHELELECTRON_HPP_ +#define TRIGGERALGS_MICHELELECTRON_TRIGGERCANDIDATEMAKERMICHELELECTRON_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" + +//#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/triggercandidatemakerhorizontalmuon/Nljs.hpp" + +#include +#include + +namespace triggeralgs { +class TCMakerMichelElectronAlgorithm : public TriggerCandidateMaker +{ + +public: + /// The function that gets call when there is a new activity + void process(const TriggerActivity&, std::vector&); + + void configure(const nlohmann::json& config); + + // void flush(timestamp_t, std::vector& output_tc); + +private: + class Window + { + public: + bool is_empty() const { return inputs.empty(); }; + void add(const TriggerActivity& input_ta) + { + // Add the input TA's contribution to the total ADC, increase the hit count + // of all of the channels which feature and add it to the TA list keeping the TA + // list time ordered by time_start. Preserving time order makes moving easier. + adc_integral += input_ta.adc_integral; + for (TriggerPrimitive tp : input_ta.inputs) { + channel_states[tp.channel]++; + } + // Perform binary search based on time_start. + uint16_t insert_at = 0; + for (auto ta : inputs) { + if (input_ta.time_start < ta.time_start) + break; + insert_at++; + } + inputs.insert(inputs.begin() + insert_at, input_ta); + }; + void clear() { inputs.clear(); }; + uint16_t n_channels_hit() { return channel_states.size(); }; + void move(TriggerActivity const& input_ta, timestamp_t const& window_length) + { + // Find all of the TAs in the window that need to be removed + // if the input_ta is to be added and the size of the window + // is to be conserved. + // Subtract those TAs' contribution from the total window ADC and remove their + // contributions to the hit counts. + uint32_t n_tas_to_erase = 0; + for (auto ta : inputs) { + if (!(input_ta.time_start - ta.time_start < window_length)) { + n_tas_to_erase++; + adc_integral -= ta.adc_integral; + for (TriggerPrimitive tp : ta.inputs) { + channel_states[tp.channel]--; + // If a TA being removed from the window results in a channel no longer having + // any hits, remove from the states map so map.size() can be used for number + // channel hits. + if (channel_states[tp.channel] == 0) + channel_states.erase(tp.channel); + } + } else + break; + } + // Erase the TAs from the window. + inputs.erase(inputs.begin(), inputs.begin() + n_tas_to_erase); + // Make the window start time the start time of what is now the + // first TA. + if (inputs.size() != 0) { + time_start = inputs.front().time_start; + add(input_ta); + } else + add(input_ta); + } + void reset(TriggerActivity const& input_ta) + { + // Empty the channel and TA lists. + channel_states.clear(); + inputs.clear(); + // Set the start time of the window to be the start time of the + // input_ta. + time_start = input_ta.time_start; + // Start the total ADC integral. + adc_integral = input_ta.adc_integral; + // Start hit count for the hit channels. + for (TriggerPrimitive tp : input_ta.inputs) { + channel_states[tp.channel]++; + } + // Add the input TA to the TA list. + inputs.push_back(input_ta); + } + friend std::ostream& operator<<(std::ostream& os, const Window& window) + { + if (window.is_empty()) + os << "Window is empty!\n"; + // else{ + // os << "Window start: " << window.time_start << ", end: " << window.inputs.back().time_start; + // os << ". Total of: " << window.adc_integral << " ADC counts with " << window.inputs.size() << " TPs.\n"; + // os << window.channel_states.size() << " independent channels have hits.\n"; + // } + return os; + }; + + timestamp_t time_start; + uint64_t adc_integral; + std::unordered_map channel_states; + std::vector inputs; + }; + + TriggerCandidate construct_tc() const; + bool check_adjacency() const; + + Window m_current_window; + uint64_t m_activity_count = 0; // NOLINT(build/unsigned) + + // Configurable parameters. + // triggercandidatemakerhorizontalmuon::ConfParams m_conf; + // If both m_trigger_on_adc and m_trigger_on_n_channels is false, nothing is done at + // the candidate level, candidates are made 1 for 1 with activities. + // Use any other combination of m_trigger_on_adc and m_trigger_on_n_channels with caution, + // they have not been tested. + bool m_trigger_on_adc = false; + bool m_trigger_on_n_channels = false; + uint32_t m_adc_threshold = 1200000; + uint16_t m_n_channels_threshold = 600; // 80ish for frames, O(200 - 600) for tpslink + timestamp_t m_window_length = 80000; + int tc_number = 0; + // Might not be the best type for this map. + // std::unordered_map,channel_t> m_channel_map; + + // For debugging purposes. + void add_window_to_record(Window window); + void dump_window_record(); + std::vector m_window_record; +}; +} // namespace triggeralgs + +#endif // TRIGGERALGS_MICHELELECTRON_TRIGGERCANDIDATEMAKERMICHELELECTRON_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/README.md b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/README.md new file mode 100644 index 0000000..4d55f38 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/README.md @@ -0,0 +1,27 @@ +# Plane Coincidence Trigger + + - Serves as introductory low energy event trigger algorithm template. Based on the same method of continuous scanning of time windows containing TPs. + - In the past we have used only collection channel TPC hits to trigger on, for example, horizontal muons in the VD ColdBox runs at CERN. With the introduction of induction TPs used in this algorithm, it is hoped they can be leveraged for the identification and triggering on candidate low energy events. + - The current approach to developing this algorithm is the simulation of TPC TPs in LArSoft, using Klaudia's branch of [duneana](https://github.com/DUNE/duneana/tree/feature/kwawrows_TriggerTPGen/duneana/DAQSimAna). The output TPs can be played through the `trigger` +[replay app](https://github.com/DUNE-DAQ/trigger/tree/develop/python/trigger/replay_tp_to_chain), which can be used to test the functionality of algorithms offline, in `dunedaq` code. + +## Trigger Activity Maker +- We have 3 instances of the `Window` class, as used in the Horizontal Muon Algorithm (HMA). Each `Window` will contain the TPs received in a configurable amount of time from one of three TPC planes. Currently we first require an ADC spike above pure radiological background and noise hits (from simulation) which is the sum of ADC integrals of all windows. Second, this must be coupled with a short primary ionisation track in the collection plane, presumably caused by a Michel electron or SN event. The adjacency checking of the tried and tested Horizontal Muon Algorithm is used here. + +#### Adjacency Checking Function + - This function returns the adjacency value for the current window, where adjacency + is defined as the maximum number of consecutive wires containing hits. It accepts + a configurable tolerance paramter, which allows up to adj_tolerance missing hits + on adjacent wires before restarting the adjacency count. The maximum gap is 4 which + comes from tuning on December 2021 coldbox data, and June 2022 coldbox runs. + + - Adjcancency Tolerance = Number of times prepared to skip missed hits before resetting + the adjacency count. This accounts for things like dead channels / missed TPs. The + maximum gap is 4 which comes from tuning on December 2021 coldbox data, and June 2022 + coldbox runs. + +## Trigger Candidate Maker +- At the moment, we use a trivial logic, by which we mean that there is a one-to-one map between emitted TAs and TCs. More complex triggering logic will be used in the future, when we want to cluster TAs from multiple detector elements (APAs). + + - For a talk on the related HMA, please see https://indico.fnal.gov/event/51502/contributions/226506/attachments/148509/190809/211019_FDDS_HorizontalMuon.pdf + diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/TAMakerPlaneCoincidenceAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/TAMakerPlaneCoincidenceAlgorithm.hpp new file mode 100644 index 0000000..17c71bd --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/TAMakerPlaneCoincidenceAlgorithm.hpp @@ -0,0 +1,68 @@ +/** + * @file TAMakerPlaneCoincidenceAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_PLANECOINCIDENCE_TRIGGERACTIVITYMAKERPLANECOINCIDENCE_HPP_ +#define TRIGGERALGS_PLANECOINCIDENCE_TRIGGERACTIVITYMAKERPLANECOINCIDENCE_HPP_ + +#include "dunetrigger/channelmaps/OfflineTPCChannelMap.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TPWindow.hpp" +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace triggeralgs { +class TAMakerPlaneCoincidenceAlgorithm : public TriggerActivityMaker +{ +public: + void process(const TriggerPrimitive& input_tp, std::vector& output_ta); + void configure(const nlohmann::json& config); + +private: + TriggerActivity construct_ta(TPWindow m_current_window) const; + uint16_t check_adjacency(TPWindow window) const; // Returns longest string of adjacent collection hits in window + + TPWindow m_current_window; // Possibly redundant for this alg? + uint64_t m_primitive_count = 0; + int check_sot(TPWindow m_current_window) const; + //void clearWindows(TriggerPrimitive const input_tp); // Function to clear or reset all windows, according to TP channel + + // Make 3 instances of the Window class. One for each view plane. + TPWindow m_collection_window; // Z + TPWindow m_induction1_window; // U + TPWindow m_induction2_window; // Y + + // Configurable parameters. + std::string m_channel_map_name = "VDColdboxTPCChannelMap"; // Default is coldbox + uint16_t m_adjacency_threshold = 15; // Default is 15 wire track for testing + int m_max_adjacency = 0; // The maximum adjacency seen so far in any window + uint32_t m_sot_threshold = 2000; // Work out good values for this + uint32_t m_adc_threshold = 300000; // AbsRunningSum HF Alg Finds Induction ADC ~10x higher + uint16_t m_adj_tolerance = 5; // Adjacency tolerance - default is 3 from coldbox testing. + int index = 0; + uint16_t ta_adc = 0; + uint16_t ta_channels = 0; + timestamp_t m_window_length = 3000; // Shouldn't exceed the max drift + + // Channel map object, for separating TPs by the plane view they come from + std::shared_ptr channelMap = dunedaq::detchannelmaps::make_tpc_map(m_channel_map_name); + + // For debugging and performance study purposes. + void add_window_to_record(TPWindow window); + void dump_window_record(); + void dump_tp(TriggerPrimitive const& input_tp); + std::vector m_window_record; +}; +} // namespace triggeralgs +#endif // TRIGGERALGS_PLANECOINCIDENCE_TRIGGERACTIVITYMAKERPLANECOINCIDENCE_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/TCMakerPlaneCoincidenceAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/TCMakerPlaneCoincidenceAlgorithm.hpp new file mode 100644 index 0000000..438fe08 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/TCMakerPlaneCoincidenceAlgorithm.hpp @@ -0,0 +1,48 @@ +/** + * @file TCMakerPlaneCoincidenceAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_PLANECOINCIDENCE_TRIGGERCANDIDATEMAKERPLANECOINCIDENCE_HPP_ +#define TRIGGERALGS_PLANECOINCIDENCE_TRIGGERCANDIDATEMAKERPLANECOINCIDENCE_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TAWindow.hpp" +#include +#include + +namespace triggeralgs { +class TCMakerPlaneCoincidenceAlgorithm : public TriggerCandidateMaker +{ + +public: + // The function that gets called when there is a new activity + void process(const TriggerActivity&, std::vector&); + void configure(const nlohmann::json& config); + +private: + + TriggerCandidate construct_tc() const; + bool check_adjacency() const; + + TAWindow m_current_window; + uint64_t m_activity_count = 0; // NOLINT(build/unsigned) + + // Configurable parameters. + bool m_trigger_on_adc = false; + bool m_trigger_on_n_channels = false; + uint32_t m_adc_threshold = 1200000; + uint16_t m_n_channels_threshold = 600; // 80ish for frames, O(200 - 600) for tpslink + timestamp_t m_window_length = 80000; + int tc_number = 0; + + // For debugging and performance study purposes. + void add_window_to_record(TAWindow window); + void dump_window_record(); + std::vector m_window_record; +}; +} // namespace triggeralgs +#endif // TRIGGERALGS_PLANECOINCIDENCE_TRIGGERCANDIDATEMAKERPLANECOINCIDENCE_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Prescale/TAMakerPrescaleAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Prescale/TAMakerPrescaleAlgorithm.hpp new file mode 100644 index 0000000..63bad2e --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Prescale/TAMakerPrescaleAlgorithm.hpp @@ -0,0 +1,29 @@ +/** + * @file TAMakerPrescaleAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_PRESCALE_TRIGGERACTIVITYMAKERPRESCALE_HPP_ +#define TRIGGERALGS_PRESCALE_TRIGGERACTIVITYMAKERPRESCALE_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" + +#include + +namespace triggeralgs { +class TAMakerPrescaleAlgorithm : public TriggerActivityMaker +{ + +public: + void process(const TriggerPrimitive& input_tp, std::vector& output_ta); + + void configure(const nlohmann::json &config); + +private: +}; +} // namespace triggeralgs + +#endif // TRIGGERALGS_PRESCALE_TRIGGERACTIVITYMAKERPRESCALE_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Prescale/TCMakerPrescaleAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Prescale/TCMakerPrescaleAlgorithm.hpp new file mode 100644 index 0000000..bb9f902 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Prescale/TCMakerPrescaleAlgorithm.hpp @@ -0,0 +1,32 @@ +/** + * @file TCMakerPrescaleAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_PRESCALE_TRIGGERCANDIDATEMAKERPRESCALE_HPP_ +#define TRIGGERALGS_PRESCALE_TRIGGERCANDIDATEMAKERPRESCALE_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" + +#include + +namespace triggeralgs { +class TCMakerPrescaleAlgorithm : public TriggerCandidateMaker +{ + +public: + /// The function that gets call when there is a new activity + void process(const TriggerActivity&, std::vector&); + + void configure(const nlohmann::json &config); + +private: + +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_PRESCALE_TRIGGERCANDIDATEMAKERPRESCALE_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TAMakerSupernovaAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TAMakerSupernovaAlgorithm.hpp new file mode 100644 index 0000000..a9981d7 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TAMakerSupernovaAlgorithm.hpp @@ -0,0 +1,99 @@ +/** + * @file TAMakerSupernovaAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERACTIVITYMAKERSUPERNOVA_HPP_ +#define TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERACTIVITYMAKERSUPERNOVA_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" + +#include +#include +#include + +namespace triggeralgs { +class TAMakerSupernovaAlgorithm : public TriggerActivityMaker +{ + + /// This activity maker makes an activity with all the trigger primitives + inline bool is_time_consistent(const TriggerPrimitive& input_tp) const + { + timestamp_t tend = input_tp.time_start + input_tp.samples_over_threshold * 32; // FIXME: Replace the hard-coded SOT to TOT scaling. + + bool is_close_to_edge = (m_time_tolerance > abs(timestamp_diff_t(input_tp.time_start) - timestamp_diff_t(m_time_end))) || + m_time_tolerance > abs(timestamp_diff_t(input_tp.time_start) - timestamp_diff_t(m_time_start)) || + m_time_tolerance > abs(timestamp_diff_t(tend) - timestamp_diff_t(m_time_end)) || + m_time_tolerance > abs(timestamp_diff_t(tend) - timestamp_diff_t(m_time_start)); + + bool is_in_between_edge = ((tend > m_time_start && tend < m_time_end) || + (input_tp.time_start > m_time_start && input_tp.time_start < m_time_end)); + + return is_in_between_edge || is_close_to_edge; + } + + inline bool is_channel_consistent(const TriggerPrimitive& input_tp) const + { + + bool is_close_to_edge = (m_channel_tolerance > abs(channel_diff_t(input_tp.channel) - m_channel_end) || + m_channel_tolerance > abs(channel_diff_t(input_tp.channel) - m_channel_start)); + + bool is_in_between_edge = (input_tp.channel > m_channel_start && input_tp.channel < m_channel_end); + + return is_in_between_edge || is_close_to_edge; + } + +public: + void process(const TriggerPrimitive& input_tp, std::vector& output_ta) override; + + void flush(timestamp_t, std::vector& tas) override { tas.push_back(MakeTriggerActivity()); } + +protected: + timestamp_diff_t m_time_tolerance = + 250; /// Maximum tolerated time difference between two primitives to form an activity (in 50 MHz clock ticks) + channel_t m_channel_tolerance = + 2; /// Maximum tolerated channel number difference between two primitives to form an activity + +private: + TriggerActivity MakeTriggerActivity() const + { + TriggerActivity ta; + ta.time_start = m_time_start; + ta.time_end = m_time_end; + ta.time_peak = m_time_peak; + ta.time_activity = m_time_activity; + ta.channel_start = m_channel_start; + + ta.channel_end = m_channel_end; + ta.channel_peak = m_channel_peak; + ta.adc_integral = m_adc_integral; + ta.adc_peak = m_adc_peak; + ta.detid = m_detid; + + ta.type = m_type; + ta.algorithm = m_algorithm; + ta.inputs = m_tp_list; + return ta; + } + + timestamp_t m_time_start = 0; + timestamp_t m_time_end = 0; + timestamp_t m_time_peak = 0; + timestamp_t m_time_activity = 0; + channel_diff_t m_channel_start = 0; // NOLINT(build/unsigned) + channel_diff_t m_channel_end = 0; // NOLINT(build/unsigned) + channel_diff_t m_channel_peak = 0; // NOLINT(build/unsigned) + uint64_t m_adc_integral = 0; // NOLINT(build/unsigned) + uint16_t m_adc_peak = 0; // NOLINT(build/unsigned) + detid_t m_detid = 0; // NOLINT(build/unsigned) + TriggerActivity::Type m_type = TriggerActivity::Type::kTPC; + TriggerActivity::Algorithm m_algorithm = TriggerActivity::Algorithm::kSupernova; + + std::vector m_tp_list; +}; +} // namespace triggeralgs + +#endif // TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERACTIVITYMAKERSUPERNOVA_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TCMakerSupernovaAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TCMakerSupernovaAlgorithm.hpp new file mode 100644 index 0000000..ba957f7 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TCMakerSupernovaAlgorithm.hpp @@ -0,0 +1,51 @@ +/** + * @file TCMakerSupernovaAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERCANDIDATEMAKERSUPERNOVA_HPP_ +#define TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERCANDIDATEMAKERSUPERNOVA_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp" + +#include +#include +#include +#include + +namespace triggeralgs { +class TCMakerSupernovaAlgorithm : public TriggerCandidateMaker +{ + /// This decision maker just counts the number of activities in the time_window and triggers + /// if the number of activities exceeds that. + +public: + /// The function that gets call when there is a new activity + void process(const TriggerActivity&, std::vector&); + +protected: + std::vector m_activity; + /// Slinding time window to count activities + std::atomic m_time_window = { 500'000'000 }; + /// Minimum number of activities in the time window to issue a trigger + std::atomic m_threshold = { 3 }; // NOLINT(build/unsigned) + /// Minimum number of primities in an activity + std::atomic m_hit_threshold = { 2 }; // NOLINT(build/unsigned) + + /// this function gets rid of the old activities + void FlushOldActivity(timestamp_t time_now) + { + timestamp_diff_t how_far = time_now - m_time_window; + auto end = std::remove_if( + m_activity.begin(), m_activity.end(), [how_far, this](auto& c) -> bool { return (static_cast(c.time_start) < how_far); }); + m_activity.erase(end, m_activity.end()); + } +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERCANDIDATEMAKERSUPERNOVA_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TDMakerSupernovaAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TDMakerSupernovaAlgorithm.hpp new file mode 100644 index 0000000..72d82db --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TDMakerSupernovaAlgorithm.hpp @@ -0,0 +1,50 @@ +/** + * @file TDMakerSupernovaAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERDECISIONMAKERSUPERNOVA_HPP_ +#define TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERDECISIONMAKERSUPERNOVA_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerDecisionMaker.hpp" +#include "detdataformats/trigger/Types2.hpp" + +#include +#include +#include +#include + +namespace triggeralgs { +class TDMakerSupernovaAlgorithm : public TriggerDecisionMaker +{ + /// This decision maker just spits out the trigger candidates + +public: + /// The function that returns the final trigger decision (copy of a candidate for now) + void operator()(const TriggerCandidate&, std::vector&); + +protected: + std::vector m_candidate; + /// Sliding time window to count activities + std::atomic m_time_window = { 500'000'000 }; + /// Minimum number of activities in the time window to issue a trigger + std::atomic m_threshold = { 1 }; // NOLINT(build/unsigned) + /// Minimum number of primities in an activity + std::atomic m_hit_threshold = { 1 }; // NOLINT(build/unsigned) + + /// this function gets rid of the old activities + void FlushOldCandidate(dunedaq::trgdataformats2::timestamp_t time_now) + { + dunedaq::trgdataformats2::timestamp_diff_t how_far = time_now - m_time_window; + auto end = std::remove_if( + m_candidate.begin(), m_candidate.end(), [how_far, this](auto& c) -> bool { return (static_cast(c.time_start) < how_far); }); + m_candidate.erase(end, m_candidate.end()); + } +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_SRC_TRIGGERALGS_SUPERNOVA_TRIGGERDECISIONMAKERSUPERNOVA_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TAWindow.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TAWindow.hpp new file mode 100644 index 0000000..eee9ace --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TAWindow.hpp @@ -0,0 +1,60 @@ +/* @file: TAWindow.hpp + * + * This is party of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_TAWINDOW_HPP_ +#define TRIGGERALGS_TAWINDOW_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp" + +#include +#include + +namespace triggeralgs { + +class TAWindow +{ +public: + bool is_empty() const { return inputs.empty(); }; + + /// @brief + /// Add the input TA's contribution to the total ADC, increase the hit count of + /// all of the channels which feature and add it to the TA list keeping the TA + /// list time ordered by time_start. Preserving time order makes moving easier. + /// @param input_ta + void add(const TriggerActivity& input_ta); + + /// @brief Clear all inputs + void clear(); + + uint16_t n_channels_hit() { return channel_states.size(); }; + + /// @brief + /// Find all of the TAs in the window that need to be removed + /// if the input_ta is to be added and the size of the window + /// is to be conserved. + /// Subtract those TAs' contribution from the total window ADC and remove their + /// contributions to the hit counts. + /// @param input_ta + /// @param window_length + void move(TriggerActivity const& input_ta, timestamp_t const& window_length); + + /// @brief Reset window content on the input + /// @param input_ta + void reset(TriggerActivity const& input_ta); + + friend std::ostream& operator<<(std::ostream& os, const TAWindow& window); + + timestamp_t time_start = 0; + uint64_t adc_integral = 0; + std::unordered_map channel_states; + std::vector inputs; +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_TAWINDOW_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TPWindow.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TPWindow.hpp new file mode 100644 index 0000000..ea24654 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TPWindow.hpp @@ -0,0 +1,44 @@ +/* @file: TPWindow.hpp + * + * This is party of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_TPWINDOW_HPP_ +#define TRIGGERALGS_TPWINDOW_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp" + +#include +#include +#include + +namespace triggeralgs { + +class TPWindow +{ +public: + bool is_empty() const; + + void add(TriggerPrimitive const& input_tp); + + void clear(); + + uint16_t n_channels_hit(); + + void move(TriggerPrimitive const& input_tp, timestamp_t const& window_length); + + void reset(TriggerPrimitive const& input_tp); + + friend std::ostream& operator<<(std::ostream& os, const TPWindow& window); + + timestamp_t time_start = 0; + uint32_t adc_integral = 0; + std::unordered_map channel_states; + std::vector inputs; +}; +} // namespace triggeralgs + +#endif // TRIGGERALGS_TPWINDOW_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivity.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivity.hpp new file mode 100644 index 0000000..3d5cc9a --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivity.hpp @@ -0,0 +1,37 @@ +/** + * @file TriggerActivity.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERACTIVITY_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERACTIVITY_HPP_ + +#include "detdataformats/trigger/TriggerActivityData2.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp" + +#include + +namespace triggeralgs { + +struct TriggerActivity : public dunedaq::trgdataformats2::TriggerActivityData +{ + TriggerActivity() = default; + TriggerActivity(const TriggerActivity&) = default; + TriggerActivity& operator=(const TriggerActivity&) = default; + TriggerActivity& operator=(TriggerActivity&&) = default; + ~TriggerActivity() = default; + + TriggerActivity(dunedaq::trgdataformats2::TriggerActivityData&& data) + : dunedaq::trgdataformats2::TriggerActivityData(std::move(data)) {} + TriggerActivity(const dunedaq::trgdataformats2::TriggerActivityData &data) + : dunedaq::trgdataformats2::TriggerActivityData(data) {} + + std::vector inputs; +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERACTIVITY_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp new file mode 100644 index 0000000..bd931e4 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp @@ -0,0 +1,27 @@ +/* @file: TriggerActivityFactory.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2023. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_TRIGGER_ACTIVITY_FACTORY_HPP_ +#define TRIGGERALGS_TRIGGER_ACTIVITY_FACTORY_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityMaker.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hpp" + +#define REGISTER_TRIGGER_ACTIVITY_MAKER(tam_name, tam_class) \ + static struct tam_class##Registrar { \ + tam_class##Registrar() { \ + TriggerActivityFactory::register_creator(tam_name, []() -> std::unique_ptr {return std::make_unique();}); \ + } \ + } tam_class##_registrar; + +namespace triggeralgs { + +class TriggerActivityFactory : public AbstractFactory {}; + +} /* namespace triggeralgs */ + +#endif // TRIGGERALGS_TRIGGER_ACTIVITY_FACTORY_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityMaker.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityMaker.hpp new file mode 100644 index 0000000..24ef019 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityMaker.hpp @@ -0,0 +1,141 @@ +/** + * @file TriggerActivityMaker.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERACTIVITYMAKER_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERACTIVITYMAKER_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Issues.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Logging.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp" + +#include +#include +#include +#include + +// TRACE_NAME to be defined in the derived TAMs +#include "TRACE/trace.h" + +namespace triggeralgs { + +class TriggerActivityMaker +{ +public: + virtual ~TriggerActivityMaker() = default; + void operator()(const TriggerPrimitive& input_tp, std::vector& output_ta) + { + // Apply TP filtering + if (!preprocess(input_tp)) { + return; + } + + // Process TP, to implement per alg triggeralgs + process(input_tp, output_ta); + + // Postprocess TA, e.g. prescaling + postprocess(output_ta); + } + + /** + * @brief TP processing function that creates & fills TAs + * + * @param input_tp[in] Input TP for the triggering algorithm + * @param output_ta[out] Output vector of TAs to fill by the algorithm + */ + virtual void process(const TriggerPrimitive& input_tp, std::vector& output_ta) = 0; + + /** + * @brief TP pre-processing/filtering + * + * Takes a TP and returns true or false depending whether we want to process + * that TP into a TA algorithm. + * + * @todo: Implement tp-filtering, e.g. SOT, plane, channel and whatnot + * @todo: Implement something smarter & more efficient if no filtering: vector of functions, or c-o-c + * + * @param[in] intput_tp input TP reference for filtering + * @return bool true if we want to keep the TP + */ + virtual bool preprocess(const TriggerPrimitive& input_tp) + { + if (input_tp.samples_over_threshold > m_max_samples_over_threshold) { + return false; + } + + return true; + } + + /** + * @brief Post-processing/filtering of the TAs, e.g. prescale + * + * Takes a vector of TAs and removes ones that we want to filter out, e.g. + * based on prescaling. + * + * @todo: Like in preprocessing: implement something more efficient, e.g. vec of tasks + * + * @param output_ta[out] output triggeractivity vector + */ + virtual void postprocess(std::vector& output_ta) + { + // Don't post-process TAs if there's no TAs made. + if (output_ta.size() == 0) { + return; + } + + // Apply prescale by erasing TAs + if (m_prescale > 1) { + for (std::vector::iterator iter = output_ta.begin(); iter != output_ta.end();) { + m_ta_count++; + + if (m_ta_count % m_prescale != 0) { + iter = output_ta.erase(iter); + continue; + } + + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "Emitting prescaled TriggerActivity " << (m_ta_count-1) + << " with time start/end/activity: " << iter->time_start + << " " << iter->time_end << " " << iter->time_activity; + ++iter; + } + } + } + + virtual void flush(timestamp_t /* until */, std::vector&) {} + virtual void configure(const nlohmann::json& config) + { + // Don't do anyting if the config does not exist + if (!config.is_object()) { + return; + } + + if (config.contains("prescale")) + m_prescale = config["prescale"]; + if (config.contains("max_samples_over_threshold")) + m_max_samples_over_threshold = config["max_samples_over_threshold"]; + + TLOG() << "[TAM]: max sot : " << m_max_samples_over_threshold; + TLOG() << "[TAM]: prescale : " << m_prescale; + } + + std::atomic m_data_vs_system_time = 0; + std::atomic m_initial_offset = 0; + + /// @brief Configurable prescale factor + uint64_t m_prescale = 1; + /// @brief TA made count for prescaling + uint64_t m_ta_count = 0; + + /// @brief Time-over-threshold TP filtering + uint32_t m_max_samples_over_threshold = std::numeric_limits::max(); +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERACTIVITYMAKER_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidate.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidate.hpp new file mode 100644 index 0000000..298a300 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidate.hpp @@ -0,0 +1,37 @@ +/** + * @file TriggerCandidate.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERCANDIDATE_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERCANDIDATE_HPP_ + +#include "detdataformats/trigger/TriggerActivityData2.hpp" +#include "detdataformats/trigger/TriggerCandidateData2.hpp" + +#include + +namespace triggeralgs { + +struct TriggerCandidate : public dunedaq::trgdataformats2::TriggerCandidateData +{ + TriggerCandidate() = default; + TriggerCandidate(const TriggerCandidate&) = default; + TriggerCandidate& operator=(const TriggerCandidate&) = default; + TriggerCandidate& operator=(TriggerCandidate&&) = default; + ~TriggerCandidate() = default; + + TriggerCandidate(dunedaq::trgdataformats2::TriggerCandidateData&& data) + : dunedaq::trgdataformats2::TriggerCandidateData(std::move(data)) {} + TriggerCandidate(const dunedaq::trgdataformats2::TriggerCandidateData &data) + : dunedaq::trgdataformats2::TriggerCandidateData(data) {} + + std::vector inputs; +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERCANDIDATE_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp new file mode 100644 index 0000000..4e0d509 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp @@ -0,0 +1,27 @@ +/* @file: TriggerCandidateFactory.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2023. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_TRIGGER_CANDIDATE_FACTORY_HPP_ +#define TRIGGERALGS_TRIGGER_CANDIDATE_FACTORY_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateMaker.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/AbstractFactory.hpp" + +#define REGISTER_TRIGGER_CANDIDATE_MAKER(tcm_name, tcm_class) \ + static struct tcm_class##Registrar { \ + tcm_class##Registrar() { \ + TriggerCandidateFactory::register_creator(tcm_name, []() -> std::unique_ptr {return std::make_unique();}); \ + } \ + } tcm_class##_registrar; + +namespace triggeralgs { + +class TriggerCandidateFactory : public AbstractFactory {}; + +} /* namespace triggeralgs */ + +#endif // TRIGGERALGS_TRIGGER_CANDIDATE_FACTORY_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateMaker.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateMaker.hpp new file mode 100644 index 0000000..fd93233 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateMaker.hpp @@ -0,0 +1,144 @@ +/** + * @file TriggerCandidateMaker.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERCANDIDATEMAKER_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERCANDIDATEMAKER_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Issues.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Logging.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidate.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp" + +#include +#include +#include +#include + +// TRACE_NAME to be defined in the derived TAMs +#include "TRACE/trace.h" + +namespace triggeralgs { + +class TriggerCandidateMaker +{ +public: + virtual ~TriggerCandidateMaker() = default; + void operator()(const TriggerActivity& input_ta, std::vector& output_tc) + { + // Apply TP filtering + if (!preprocess(input_ta)) { + return; + } + + // Process TP, to implement per alg triggeralgs + process(input_ta, output_tc); + + // Postprocess TA, e.g. prescaling + postprocess(output_tc); + } + + /** + * @brief TA processing function that creates & fills TCs + * + * @param input_ta[in] Input TA for the triggering algorithm + * @param output_tc[out] Output vector of TCs to fill by the algorithm + */ + virtual void process(const TriggerActivity& input_ta, std::vector& output_tc) = 0; + + /** + * @brief TA pre-processing/filtering + * + * @todo: Implement ta-filtering, e.g. by plane or sub-detector + * @todo: Implement something smarter & more efficient if no filtering: vector of functions, or c-o-c + * + * @param[in] intput_tp input TP reference for filtering + * @return bool true if we want to keep the TP + */ + virtual bool preprocess(const TriggerActivity&) + { + return true; + } + + /** + * @brief Post-processing/filtering of the TCs, e.g. prescale + * + * Takes a vector of TCs and removes ones that we want to filter out, e.g. + * based on prescaling. + * + * @todo: Like in preprocessing: implement something more efficient, e.g. vec of tasks + * + * @param output_tc[out] output trigger candidate vector + */ + virtual void postprocess(std::vector& output_tc) + { + // Don't post-process TCs if there's no TCs made. + if (output_tc.size() == 0) { + return; + } + + // Apply prescale by erasing TCs + if (m_prescale > 1) { + for (std::vector::iterator iter = output_tc.begin(); iter != output_tc.end();) { + m_tc_count++; + + if (m_tc_count % m_prescale != 0) { + iter = output_tc.erase(iter); + continue; + } + + TLOG_DEBUG(TLVL_DEBUG_10) << "Emitting prescaled TriggerCandidate " << (m_tc_count-1); + ++iter; + } + } + } + virtual void flush(timestamp_t /* until */, std::vector& /* output_tc */) {} + virtual void configure(const nlohmann::json& config) + { + // Don't do anyting if the config does not exist + if (!config.is_object()) { + return; + } + + if (config.contains("prescale")) { + m_prescale = config["prescale"]; + } + + if (config.contains("tc_type_name")) { + m_tc_type_out = static_cast( + dunedaq::trgdataformats2::string_to_trigger_candidate_type(config["tc_type_name"])); + } + + if (m_tc_type_out == TriggerCandidate::Type::kUnknown) { + // 27-Feb-2025, KAB: moified the following statement to check whether the configuration + // contains the tc_type_name parameter before trying to add it do the exception message. + // throw(InvalidConfiguration(ERS_HERE, "Provided an unknown output TC type: " + + // (config.contains("tc_type_name") ? + // std::string(config["tc_type_name"]) : "null"))); + } + + TLOG() << "[TCM]: prescale : " << m_prescale; + TLOG() << "[TCM]: TC type out: " << config["tc_type_name"]; + } + + std::atomic m_data_vs_system_time = 0; + std::atomic m_initial_offset = 0; + + /// @brief Configurable prescale factor + uint64_t m_prescale = 1; + /// @brief TC made count for prescaling + uint64_t m_tc_count = 0; + + /// @brief Configurable TC type output + TriggerCandidate::Type m_tc_type_out = TriggerCandidate::Type::kUnknown; + +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERCANDIDATEMAKER_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerDecision.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerDecision.hpp new file mode 100644 index 0000000..fd197c5 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerDecision.hpp @@ -0,0 +1,35 @@ +/** + * @file TriggerDecision.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERDECISION_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERDECISION_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidate.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp" + +#include +#include + +namespace triggeralgs { +struct TriggerDecision +{ + timestamp_t time_start = { 0 }; + timestamp_t time_end = { 0 }; + timestamp_t time_trigger = { 0 }; + trigger_number_t trigger_number = { 0 }; + uint32_t run_number = { 0 }; // NOLINT(build/unsigned) + uint32_t subrun_number = { 0 }; // NOLINT(build/unsigned) + uint32_t type = { 0 }; // NOLINT(build/unsigned) + uint32_t algorithm = { 0 }; // NOLINT(build/unsigned) + version_t version = { 0 }; // NOLINT(build/unsigned) + + std::vector tc_list; +}; +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERDECISION_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerDecisionMaker.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerDecisionMaker.hpp new file mode 100644 index 0000000..666c9e7 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerDecisionMaker.hpp @@ -0,0 +1,35 @@ +/** + * @file TriggerDecisionMaker.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERDECISIONMAKER_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERDECISIONMAKER_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Issues.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Logging.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidate.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerDecision.hpp" + +#include +#include +#include +#include + +namespace triggeralgs { + +class TriggerDecisionMaker +{ +public: + virtual ~TriggerDecisionMaker() = default; + virtual void operator()(const TriggerCandidate& input_tc, std::vector& output_tds) = 0; + virtual void flush(std::vector&) {} + virtual void configure(const nlohmann::json&) {} +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERDECISIONMAKER_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerObjectOverlay.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerObjectOverlay.hpp new file mode 100644 index 0000000..44255af --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerObjectOverlay.hpp @@ -0,0 +1,115 @@ +/** + * @file TriggerObjectOverlay.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGEROBJECTOVERLAY_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGEROBJECTOVERLAY_HPP_ + + +#include "detdataformats/trigger/TriggerActivityData2.hpp" +#include "detdataformats/trigger/TriggerObjectOverlay2.hpp" + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidate.hpp" + +namespace triggeralgs { + +// TypeToOverlayType acts as a "map" from a type to its overlay type +// (eg from TriggerCandidate to dunedaq::trgdataformats2::TriggerCandidate). The point of +// having this is so that we can call the various overlay conversion +// functions below without having to explicitly specify the template +// arguments. An alternative way to do this would be to have +// TriggerActivity and TriggerCandidate each contain a using declaration +// like `using overlay_t = dunedaq::trgdataformats2::Trigger(Activity|Candidate);`, but I +// couldn't figure out the right forward declaration for the overlay +// types in the TriggerCandidate/TriggerActivity header files +template +struct TypeToOverlayType; + +template<> +struct TypeToOverlayType +{ + using overlay_t = dunedaq::trgdataformats2::TriggerActivity; + using data_t = dunedaq::trgdataformats2::TriggerActivityData; +}; + +template<> +struct TypeToOverlayType +{ + using overlay_t = dunedaq::trgdataformats2::TriggerCandidate; + using data_t = dunedaq::trgdataformats2::TriggerCandidateData; +}; + +// Populate a TriggerObjectOverlay in `buffer`, created from +// `object`. The necessary size for the buffer can be found with +// `get_overlay_nbytes()` +template::overlay_t, + class Data = typename TypeToOverlayType::data_t> +void +write_overlay(const Object& object, void* buffer) +{ + Overlay* overlay = reinterpret_cast(buffer); + overlay->data = static_cast(object); + overlay->n_inputs = object.inputs.size(); + for (size_t i = 0; i < object.inputs.size(); ++i) { + overlay->inputs[i] = object.inputs[i]; + } +} + +// Calculate the size of buffer (in bytes) required to store an +// overlay created from `object` +template::overlay_t> +size_t +get_overlay_nbytes(const Object& object) +{ + // Need to check that this is actually right: what does sizeof + // return when the class contains a flexible array member? Seems to + // work in unit tests, so probably this is right + return sizeof(Overlay) + object.inputs.size() * sizeof(typename Overlay::input_t); +} + +// Given an overlay object (dunedaq::trgdataformats2::TriggerActivity or +// dunedaq::trgdataformats2::TriggerCandidate), create a corresponding non-overlay object +// (triggeralgs::TriggerActivity or triggeralgs::TriggerCandidate) with the same contents, and return it +template::overlay_t, + class Data = typename TypeToOverlayType::data_t> +Object +read_overlay(const Overlay& overlay) +{ + Object ret; + // overlay.data is a Trigger(Activity|Candidate)Data, which is the + // base class of Trigger(Activity|Candidate). So we want to set the + // base-class part of `ret` to `overlay.data`, which is what the + // static_cast is for. We have to do the cast on the pointer to get + // reference semantics (without the &, we get a _copy_ of ret, which + // is not what we want) + *static_cast(&ret) = overlay.data; + for (uint64_t i = 0; i < overlay.n_inputs; ++i) { + ret.inputs.push_back(overlay.inputs[i]); + } + return ret; +} + +// Given a buffer containing an overlay object (dunedaq::trgdataformats2::TriggerActivity +// or dunedaq::trgdataformats2::TriggerCandidate), create a corresponding non-overlay +// object (triggeralgs::TriggerActivity or triggeralgs::TriggerCandidate) with the same +// contents, and return it. This function requires the return type to +// be explicitly specified as a template argument, unlike the other +// functions in this file. Eg +// +// TriggerActivity activity_read = read_overlay_from_buffer(buffer); +template::overlay_t> +Object +read_overlay_from_buffer(const void* buffer) +{ + return read_overlay(*reinterpret_cast(buffer)); +} + +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGEROBJECTOVERLAY_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp new file mode 100644 index 0000000..1393add --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp @@ -0,0 +1,26 @@ +/** + * @file TriggerPrimitive.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERPRIMITIVE_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERPRIMITIVE_HPP_ + +#include "detdataformats/trigger/TriggerPrimitive2.hpp" + +namespace triggeralgs { +// TriggerPrimitive looks a bit difference to TriggerActivity and +// TriggerCandidate: the latter two have distinct overlay and +// non-overlay versions, but TriggerPrimitive does not. So whereas TA +// and TC have (non-overlay) definitions in triggeralgs, TP has a +// definition only in detdataformats. So we just copy it here so that +// references to TP, TA and TC in triggeralgs and downstream code +// "look" the same +using TriggerPrimitive = dunedaq::trgdataformats2::TriggerPrimitive; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERPRIMITIVE_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitiveMaker.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitiveMaker.hpp new file mode 100644 index 0000000..0e33f20 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitiveMaker.hpp @@ -0,0 +1,32 @@ +/** + * @file TriggerDecisionMaker.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERPRIMITIVEMAKER_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERPRIMITIVEMAKER_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Issues.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Logging.hpp" +#include "detdataformats/trigger/TriggerPrimitive.hpp" + +#include +#include + +namespace triggeralgs { + +class TriggerPrimitiveMaker +{ +public: + virtual ~TriggerPrimitiveMaker() = default; + virtual void operator()(const void* input_rawdata, std::vector& output_tp) = 0; + virtual void flush(std::vector&) {} + virtual void configure(const nlohmann::json&) {} +}; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_TRIGGERPRIMITIVEMAKER_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp new file mode 100644 index 0000000..64af0d3 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp @@ -0,0 +1,26 @@ +/** + * @file Types.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_INCLUDE_TRIGGERALGS_TYPES_HPP_ +#define TRIGGERALGS_INCLUDE_TRIGGERALGS_TYPES_HPP_ + +#include "detdataformats/trigger/Types2.hpp" + +namespace triggeralgs { + +using timestamp_t = dunedaq::trgdataformats2::timestamp_t; +using timestamp_diff_t = dunedaq::trgdataformats2::timestamp_diff_t; +using detid_t = dunedaq::trgdataformats2::detid_t; +using trigger_number_t = dunedaq::trgdataformats2::trigger_number_t; +using channel_t = dunedaq::trgdataformats2::channel_t; +using channel_diff_t = dunedaq::trgdataformats2::channel_diff_t; +using version_t = dunedaq::trgdataformats2::version_t; + +} // namespace triggeralgs + +#endif // TRIGGERALGS_INCLUDE_TRIGGERALGS_TYPES_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/Hit.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/Hit.hpp new file mode 100644 index 0000000..d2337d9 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/Hit.hpp @@ -0,0 +1,131 @@ +#pragma once + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp" +#include +#include +#include + +namespace triggeralgs { +namespace dbscan { +//====================================================================== + +// Special "cluster numbers" for hits that are not (yet) in a cluster +const int kNoise = -2; +const int kUndefined = -1; + +//====================================================================== + +// Hit classifications in the DBSCAN scheme +enum class Connectedness +{ + // clang-format off + kUndefined, + kNoise, // Fewer than minPts neighbours, not in a cluster + kCore, // minPts neighbours or more + kEdge // Fewer than minPts neighbours, part of a cluster + // clang-format on +}; + +//====================================================================== + +// As new hits arrive, they push forward the "current" time, and +// eventually a given hit or cluster will know that it cannot be +// modified any further. A hit becomes kComplete when its time is so +// far behind the current time that new hits cannot be neighbours of +// it. A cluster becomes kComplete when its latest hit is complete +enum class Completeness +{ + kIncomplete, + kComplete, +}; + +class Hit; + +//====================================================================== + +// An array of unique hits, sorted by time. The actual container +// implementation is a std::vector, which seems to be faster than a +// std::set (needs rechecking) +class HitSet +{ +public: + HitSet(); + + // Insert a hit in the set, if not already present. Keeps the + // array sorted by time + void insert(Hit* h); + + std::vector::iterator begin() { return hits.begin(); } + std::vector::iterator end() { return hits.end(); } + + std::vector::const_iterator begin() const { return hits.cbegin(); } + std::vector::const_iterator end() const { return hits.cend(); } + + void clear() { hits.clear(); } + + size_t size() const { return hits.size(); } + + std::vector hits; +}; + +//====================================================================== +struct Hit +{ + Hit(float _time, int _chan, const triggeralgs::TriggerPrimitive* _prim=nullptr); + + void reset(float _time, int _chan, const triggeralgs::TriggerPrimitive* _prim=nullptr); + // Add hit `other` to this hit's list of neighbours if they are + // closer than `eps`. Return true if so + bool add_potential_neighbour(Hit* other, float eps, int minPts); + + float time; + int chan, cluster; + Connectedness connectedness; + HitSet neighbours; + triggeralgs::TriggerPrimitive primitive; +}; + +//====================================================================== +inline float +manhattan_distance(const Hit& p, const Hit& q) +{ + return fabs((p.time - q.time)) + fabs(p.chan - q.chan); +} + +//====================================================================== +template +inline T +sqr(T x) +{ + return x * x; +} + +//====================================================================== +inline float +euclidean_distance(const Hit& p, const Hit& q) +{ + return std::sqrt(sqr(p.time - q.time) + sqr(p.chan - q.chan)); +} + +//====================================================================== +inline float +euclidean_distance_sqr(const Hit& p, const Hit& q) +{ + return sqr(p.time - q.time) + sqr(p.chan - q.chan); +} + +//====================================================================== +inline bool +time_comp_lower(const Hit* hit, const float t) +{ + return hit->time < t; +} + +} +} +// Local Variables: +// mode: c++ +// c-basic-offset: 4 +// c-file-style: "linux" +// End: diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/TAMakerDBSCANAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/TAMakerDBSCANAlgorithm.hpp new file mode 100644 index 0000000..2e67b81 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/TAMakerDBSCANAlgorithm.hpp @@ -0,0 +1,37 @@ +/** + * @file TAMakerDBSCANAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_DBSCAN_TRIGGERACTIVITYMAKERDBSCAN_HPP_ +#define TRIGGERALGS_DBSCAN_TRIGGERACTIVITYMAKERDBSCAN_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/dbscan.hpp" + +#include +#include + +namespace triggeralgs { +class TAMakerDBSCANAlgorithm : public TriggerActivityMaker +{ + +public: + void process(const TriggerPrimitive& input_tp, std::vector& output_ta); + + void configure(const nlohmann::json &config); + +private: + int m_eps{10}; + int m_min_pts{3}; // Minimum number of points to form a cluster + timestamp_t m_first_timestamp{0}; + timestamp_t m_prev_timestamp{0}; + std::vector m_dbscan_clusters; + std::unique_ptr m_dbscan; +}; +} // namespace triggeralgs + +#endif // TRIGGERALGS_PRESCALE_TRIGGERACTIVITYMAKERPRESCALE_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/TCMakerDBSCANAlgorithm.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/TCMakerDBSCANAlgorithm.hpp new file mode 100644 index 0000000..bd16013 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/TCMakerDBSCANAlgorithm.hpp @@ -0,0 +1,35 @@ +/** + * @file TCMakerDBSCANAlgorithm.hpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#ifndef TRIGGERALGS_DBSCAN_TRIGGERCANDIDATEMAKERDBSCAN_HPP_ +#define TRIGGERALGS_DBSCAN_TRIGGERCANDIDATEMAKERDBSCAN_HPP_ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/dbscan.hpp" + +#include +#include + +namespace triggeralgs { +class TCMakerDBSCANAlgorithm : public TriggerCandidateMaker +{ + +public: + void process(const TriggerActivity& input_ta, std::vector& output_tc); + void configure(const nlohmann::json &config); + +private: + void set_new_tc(const TriggerActivity& input_ta); + void set_tc_attributes(); + TriggerCandidate m_current_tc; + uint16_t m_current_tp_count; + uint16_t m_max_tp_count = 1000; // Produce a TC when this count is exceeded. AEO: Arbitrary choice of 1000. +}; +} // namespace triggeralgs + +#endif // TRIGGERALGS_DBSCAN_TRIGGERCANDIDATEMAKERPRESCALE_HPP_ diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/dbscan.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/dbscan.hpp new file mode 100644 index 0000000..a8b16ba --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/dbscan.hpp @@ -0,0 +1,112 @@ +#pragma once + +#include +#include +#include +#include // For std::lower_bound +#include +#include + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/Hit.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp" + +namespace triggeralgs { +namespace dbscan { +//====================================================================== +// Find the eps-neighbours of hit q, assuming that the hits vector is sorted by +// time +int +neighbours_sorted(const std::vector& hits, Hit& q, float eps, int minPts); + +//====================================================================== +struct Cluster +{ + Cluster(int index_) + : index{ index_ } + {} + // The index of this cluster + int index{ -1 }; + // A cluster is kComplete if its hits are all kComplete, so no + // newly-arriving hit could be a neighbour of any hit in the + // cluster + Completeness completeness{ Completeness::kIncomplete }; + // The latest time of any hit in the cluster + float latest_time{ 0 }; + // The latest (largest time) "core" point in the cluster + Hit* latest_core_point{ nullptr }; + // The hits in this cluster + HitSet hits; + + // Add hit if it's a neighbour of a hit already in the + // cluster. Precondition: time of new_hit is >= the time of any + // hit in the cluster. Returns true if the hit was added + bool maybe_add_new_hit(Hit* new_hit, float eps, int minPts); + + // Add the hit `h` to this cluster + void add_hit(Hit* h); + + // Steal all of the hits from cluster `other` and merge them into + // this cluster + void steal_hits(Cluster& other); +}; + +//====================================================================== +// +// Modified DBSCAN algorithm that takes one hit at a time, with the requirement +// that the hits are passed in time order +class IncrementalDBSCAN +{ +public: + IncrementalDBSCAN(float eps, unsigned int minPts, size_t pool_size=100000) + : m_eps(eps) + , m_minPts(minPts) + , m_pool_begin(0) + , m_pool_end(0) + { + for(size_t i=0; i* completed_clusters=nullptr); + + void add_point(float time, float channel, std::vector* completed_clusters=nullptr); + + // Add a new hit. The hit time *must* be >= the time of all hits + // previously added + void add_hit(Hit* new_hit, std::vector* completed_clusters=nullptr); + + void trim_hits(); + + std::vector get_hits() const { return m_hits; } + + std::map get_clusters() const { return m_clusters; } + + uint64_t get_first_prim_time() const { return m_first_prim_time; } + +private: + //====================================================================== + // + // Starting from `seed_hit`, find all the reachable hits and add them + // to `cluster` + void cluster_reachable(Hit* seed_hit, Cluster& cluster); + + float m_eps; + float m_minPts; + std::vector m_hit_pool; + size_t m_pool_begin, m_pool_end; + std::vector m_hits; // All the hits we've seen so far, in time order + float m_latest_time{ 0 }; // The latest time of a hit in the vector of hits + uint64_t m_first_prim_time{0}; + std::map + m_clusters; // All of the currently-active (ie, kIncomplete) clusters +}; + +} +} + +// Local Variables: +// mode: c++ +// c-basic-offset: 4 +// c-file-style: "linux" +// End: diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerADCSimpleWindowAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerADCSimpleWindowAlgorithm.cpp new file mode 100644 index 0000000..718e8e6 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerADCSimpleWindowAlgorithm.cpp @@ -0,0 +1,108 @@ +/** + * @file TAMakerADCSimpleWindowAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/TAMakerADCSimpleWindowAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TAMakerADCSimpleWindowAlgorithm" + +#include + + +using namespace triggeralgs; +using Logging::TLVL_DEBUG_ALL; +using Logging::TLVL_DEBUG_HIGH; +using Logging::TLVL_DEBUG_LOW; +using Logging::TLVL_IMPORTANT; + +void +TAMakerADCSimpleWindowAlgorithm::process(const TriggerPrimitive& input_tp, std::vector& output_ta) +{ + + // The first time operator is called, reset + // window object. + if(m_current_window.is_empty()){ + m_current_window.reset(input_tp); + m_primitive_count++; + return; + } + + // If the difference between the current TP's start time and the start of the window + // is less than the specified window size, add the TP to the window. + if((input_tp.time_start - m_current_window.time_start) < m_window_length){ + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TAM:ADCSW] Window not yet complete, adding the input_tp to the window."; + m_current_window.add(input_tp); + } + // If the addition of the current TP to the window would make it longer + // than the specified window length, don't add it but check whether the sum of all adc in + // the existing window is above the specified threshold. If it is, make a TA and start + // a fresh window with the current TP. + else if(m_current_window.adc_integral > m_adc_threshold){ + TLOG_DEBUG(TLVL_DEBUG_LOW) << "[TAM:ADCSW] ADC integral in window is greater than specified threshold."; + output_ta.push_back(construct_ta()); + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TAM:ADCSW] Resetting window with input_tp."; + m_current_window.reset(input_tp); + } + // If it is not, move the window along. + else{ + TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TAM:ADCSW] Window is at required length but adc threshold not met, shifting window along."; + m_current_window.move(input_tp, m_window_length); + } + + TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TAM:ADCSW] " << m_current_window; + + m_primitive_count++; + + return; +} + +void +TAMakerADCSimpleWindowAlgorithm::configure(const nlohmann::json& config) +{ + TriggerActivityMaker::configure(config); + + //FIXME use some schema here + if (config.is_object()){ + if (config.contains("window_length")) m_window_length = config["window_length"]; + if (config.contains("adc_threshold")) m_adc_threshold = config["adc_threshold"]; + } + else{ + TLOG_DEBUG(TLVL_IMPORTANT) << "[TAM:ADCSW] The DEFAULT values of window_length and adc_threshold are being used."; + } + TLOG_DEBUG(TLVL_IMPORTANT) << "[TAM:ADCSW] If the total ADC of trigger primitives with times within a " + << m_window_length << " tick time window is above " << m_adc_threshold << " counts, a trigger will be issued."; +} + +TriggerActivity +TAMakerADCSimpleWindowAlgorithm::construct_ta() const +{ + TLOG_DEBUG(TLVL_DEBUG_LOW) << "[TAM:ADCSW] I am constructing a trigger activity!"; + //TLOG_DEBUG(TRACE_NAME) << m_current_window; + + TriggerPrimitive latest_tp_in_window = m_current_window.tp_list.back(); + // The time_peak, time_activity, channel_* and adc_peak fields of this TA are irrelevent + // for the purpose of this trigger alg. + TriggerActivity ta; + ta.time_start = m_current_window.time_start; + ta.time_end = latest_tp_in_window.time_start + latest_tp_in_window.samples_over_threshold * 32; // FIXME: Replace the hard-coded SOT to TOT scaling. + ta.time_peak = latest_tp_in_window.samples_to_peak * 32 + latest_tp_in_window.time_start; // FIXME: Replace STP to `time_peak` conversion. + ta.time_activity = ta.time_peak; + ta.channel_start = latest_tp_in_window.channel; + ta.channel_end = latest_tp_in_window.channel; + ta.channel_peak = latest_tp_in_window.channel; + ta.adc_integral = m_current_window.adc_integral; + ta.adc_peak = latest_tp_in_window.adc_peak; + ta.detid = latest_tp_in_window.detid; + ta.type = TriggerActivity::Type::kTPC; + ta.algorithm = TriggerActivity::Algorithm::kADCSimpleWindow; + ta.inputs = m_current_window.tp_list; + return ta; +} + +// Register algo in TA Factory +REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerADCSimpleWindowAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerBundleNAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerBundleNAlgorithm.cpp new file mode 100644 index 0000000..73964c1 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerBundleNAlgorithm.cpp @@ -0,0 +1,87 @@ +/** + * @file TAMakerBundleNAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/BundleN/TAMakerBundleNAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TAMakerBundleNAlgorithm" + +namespace triggeralgs { + +using Logging::TLVL_IMPORTANT; +using Logging::TLVL_DEBUG_HIGH; + +void TAMakerBundleNAlgorithm::set_ta_attributes() { + // Using the first TA as reference. + TriggerPrimitive first_tp = m_current_ta.inputs.front(); + TriggerPrimitive last_tp = m_current_ta.inputs.back(); + + m_current_ta.channel_start = first_tp.channel; + m_current_ta.channel_end = last_tp.channel; + + m_current_ta.time_start = first_tp.time_start; + m_current_ta.time_end = last_tp.time_start; + + m_current_ta.detid = first_tp.detid; + + m_current_ta.algorithm = TriggerActivity::Algorithm::kBundle; + m_current_ta.type = TriggerActivity::Type::kTPC; + + m_current_ta.adc_peak = 0; + for (const TriggerPrimitive& tp : m_current_ta.inputs) { + m_current_ta.adc_integral += tp.adc_integral; + if (tp.adc_peak <= m_current_ta.adc_peak) continue; + m_current_ta.adc_peak = tp.adc_peak; + m_current_ta.channel_peak = tp.channel; + m_current_ta.time_peak = tp.samples_to_peak * 32 + tp.time_start; // FIXME: Replace STP to `time_peak` conversion. + } + m_current_ta.time_activity = m_current_ta.time_peak; + return; +} + +bool TAMakerBundleNAlgorithm::bundle_condition() { + return m_current_ta.inputs.size() == m_bundle_size; +} + +void +TAMakerBundleNAlgorithm::process(const TriggerPrimitive& input_tp, std::vector& output_tas) +{ + // Expect that TPs are inherently time ordered. + m_current_ta.inputs.push_back(input_tp); + + if (bundle_condition()) { + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TA:BN] Emitting BundleN TA with " << m_current_ta.inputs.size() << " TPs."; + set_ta_attributes(); + output_tas.push_back(m_current_ta); + + // Reset the current. + m_current_ta = TriggerActivity(); + } + + // Should never reach this step. In this case, send it out. + if (m_current_ta.inputs.size() > m_bundle_size) { + TLOG_DEBUG(TLVL_IMPORTANT) << "[TA:BN] Emitting large BundleN TriggerActivity with " << m_current_ta.inputs.size() << " TPs."; + set_ta_attributes(); + output_tas.push_back(m_current_ta); + + // Reset the current. + m_current_ta = TriggerActivity(); + } +} + +void +TAMakerBundleNAlgorithm::configure(const nlohmann::json& config) +{ + if (config.is_object() && config.contains("bundle_size")) { + m_bundle_size = config["bundle_size"]; + } +} + +REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerBundleNAlgorithm) +} // namespace triggeralgs + diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerChannelAdjacencyAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerChannelAdjacencyAlgorithm.cpp new file mode 100644 index 0000000..27bee7f --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerChannelAdjacencyAlgorithm.cpp @@ -0,0 +1,241 @@ +/** + * @file TAMakerChannelAdjacencyAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/TAMakerChannelAdjacencyAlgorithm.hpp" +#include "TRACE/trace.h" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Logging.hpp" +#define TRACE_NAME "TAMakerChannelAdjacencyAlgorithm" +#include +#include + +using namespace triggeralgs; + +using Logging::TLVL_DEBUG_LOW; + +void +TAMakerChannelAdjacencyAlgorithm::process(const TriggerPrimitive& input_tp, + std::vector& output_ta) +{ + + // Add useful info about recived TPs here for FW and SW TPG guys. + if (m_print_tp_info) { + TLOG_DEBUG(TLVL_DEBUG_LOW) << " ########## m_current_window is reset ##########\n" + << " TP Start Time: " << input_tp.time_start << ", TP ADC Sum: " << input_tp.adc_integral + << ", TP SOT: " << input_tp.samples_over_threshold << ", TP ADC Peak: " << input_tp.adc_peak + << ", TP Offline Channel ID: " << input_tp.channel << "\n"; + } + + // 0) FIRST TP ===================================================================== + // The first time process() is called, reset the window object. + if (m_current_window.is_empty()) { + m_current_window.reset(input_tp); + return; + } + + // If the difference between the current TP's start time and the start of the window + // is less than the specified window size, add the TP to the window. + bool adj_pass = 0; // sets to true when adjacency logic is satisfied + bool window_filled = 1; // sets to true when window is ready to test the adjacency logic + if ((input_tp.time_start - m_current_window.time_start) < m_window_length) { + m_current_window.add(input_tp); + window_filled = 0; + TLOG_DEBUG(TLVL_DEBUG_LOW) << "m_current_window.time_start " << m_current_window.time_start << "\n"; + } + + else { + TPWindow win_adj_max; + + bool ta_found = 1; + while (ta_found) { + + // make m_current_window_tmp a copy of m_current_window and clear m_current_window + TPWindow m_current_window_tmp = m_current_window; + m_current_window.clear(); + + // make m_current_window a new window of non-overlapping tps (of m_current_window_tmp and win_adj_max) + for (auto tp : m_current_window_tmp.inputs) { + bool new_tp = 1; + for (auto tp_sel : win_adj_max.inputs) { + if (tp.channel == tp_sel.channel) { + new_tp = 0; + break; + } + } + if (new_tp) + m_current_window.add(tp); + } + + // check adjacency -> win_adj_max now contains only those tps that make the track + win_adj_max = check_adjacency(); + if (win_adj_max.inputs.size() > 0) { + + adj_pass = 1; + ta_found = 1; + output_ta.push_back(construct_ta(win_adj_max)); + } else + ta_found = 0; + } + if (adj_pass) + m_current_window.reset(input_tp); + } + + // if adjacency logic is not true, slide the window along using the current TP. + if (window_filled && !adj_pass) { + m_current_window.move(input_tp, m_window_length); + } + + return; +} + +void +TAMakerChannelAdjacencyAlgorithm::configure(const nlohmann::json& config) +{ + TriggerActivityMaker::configure(config); + if (config.is_object()) { + if (config.contains("window_length")) + m_window_length = config["window_length"]; + if (config.contains("adjacency_tolerance")) + m_adj_tolerance = config["adjacency_tolerance"]; + if (config.contains("adjacency_threshold")) + m_adjacency_threshold = config["adjacency_threshold"]; + if (config.contains("print_tp_info")) + m_print_tp_info = config["print_tp_info"]; + } +} + +TriggerActivity +TAMakerChannelAdjacencyAlgorithm::construct_ta(TPWindow win_adj_max) const +{ + + TriggerActivity ta; + + TriggerPrimitive last_tp = win_adj_max.inputs.back(); + + ta.time_start = last_tp.time_start; + ta.time_end = last_tp.time_start; + ta.time_peak = last_tp.samples_to_peak * 32 + last_tp.time_start; // FIXME: Replace STP to `time_peak` conversion. + ta.time_activity = ta.time_peak; + ta.channel_start = last_tp.channel; + ta.channel_end = last_tp.channel; + ta.channel_peak = last_tp.channel; + ta.adc_integral = win_adj_max.adc_integral; + ta.adc_peak = last_tp.adc_peak; + ta.detid = last_tp.detid; + ta.type = TriggerActivity::Type::kTPC; + ta.algorithm = TriggerActivity::Algorithm::kChannelAdjacency; + ta.inputs = win_adj_max.inputs; + + for (const auto& tp : ta.inputs) { + ta.time_start = std::min(ta.time_start, tp.time_start); + ta.time_end = std::max(ta.time_end, tp.time_start); + ta.channel_start = std::min(ta.channel_start, channel_t(tp.channel)); + ta.channel_end = std::max(ta.channel_end, channel_t(tp.channel)); + if (tp.adc_peak > ta.adc_peak) { + ta.time_peak = tp.samples_to_peak * 32 + tp.time_start; // FIXME: Replace STP to `time_peak` conversion. + ta.adc_peak = tp.adc_peak; + ta.channel_peak = tp.channel; + } + } + + return ta; +} + +// std::vector +TPWindow +TAMakerChannelAdjacencyAlgorithm::check_adjacency() +{ + // This function deals with tp window (m_current_window), select adjacent tps (with a channel gap from 0 to 5; sum of + // all gaps < m_adj_tolerance), checks if track length > m_adjacency_threshold: return the tp window (win_adj_max, + // which is subset of the input tp window) + + unsigned int channel = 0; // Current channel ID + unsigned int next_channel = 0; // Next channel ID + unsigned int next = 0; // The next position in the hit channels vector + unsigned int tol_count = 0; // Tolerance count, should not pass adj_tolerance + + // Generate a channelID ordered list of hit channels for this window; second element of pair is tps + std::vector> chanTPList; + for (auto tp : m_current_window.inputs) { + chanTPList.push_back(std::make_pair(channel_t(tp.channel), tp)); + } + std::sort(chanTPList.begin(), + chanTPList.end(), + [](const std::pair& a, const std::pair& b) { + return (a.first < b.first); + }); + + // ADAJACENCY LOGIC ==================================================================== + // ===================================================================================== + // Adjcancency Tolerance = Number of times prepared to skip missed hits before resetting + // the adjacency count (win_adj). This accounts for things like dead channels / missed TPs. + + // add first tp, and then if tps are on next channels (check code below to understand the definition) + TPWindow win_adj; + TPWindow win_adj_max; // if track length > m_adjacency_threshold, set win_adj_max = win_adj; return win_adj_max; + + for (int i = 0; i < chanTPList.size(); ++i) { + + win_adj_max.clear(); + + next = (i + 1) % chanTPList.size(); // Loops back when outside of channel list range + channel = chanTPList.at(i).first; + next_channel = chanTPList.at(next).first; // Next channel with a hit + + // End of vector condition. + if (next == 0) { + next_channel = channel - 1; + } + + // Skip same channel hits. + if (next_channel == channel) + continue; + + // If win_adj size == zero, add current tp + if (win_adj.inputs.size() == 0) + win_adj.add(chanTPList[i].second); + + // If next hit is on next channel, increment the adjacency count + if (next_channel - channel == 1) { + win_adj.add(chanTPList[next].second); + } + + // Allow a max gap of 5 channels (e.g., 45 and 50; 46, 47, 48, 49 are missing); increment the adjacency count + // Sum of gaps should be < adj_tolerance (e.g., if toleance is 30, the max total gap can vary from 0 to 29+4 = 33) + else if (next_channel - channel > 0 && next_channel - channel <= 5 && tol_count < m_adj_tolerance) { + win_adj.add(chanTPList[next].second); + tol_count += next_channel - channel - 1; + } + + // if track length > m_adjacency_threshold, set win_adj_max = win_adj; + else if (win_adj.inputs.size() > m_adjacency_threshold) { + win_adj_max = win_adj; + break; + } + + // If track length < m_adjacency_threshold, reset variables for next iteration. + else { + tol_count = 0; + win_adj.clear(); + } + } + + return win_adj_max; +} + +// ===================================================================================== +// Functions below this line are for debugging purposes. +// ===================================================================================== +void +TAMakerChannelAdjacencyAlgorithm::add_window_to_record(TPWindow window) +{ + m_window_record.push_back(window); + return; +} + +// Register algo in TA Factory +REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerChannelAdjacencyAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerChannelDistanceAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerChannelDistanceAlgorithm.cpp new file mode 100644 index 0000000..96319e8 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerChannelDistanceAlgorithm.cpp @@ -0,0 +1,104 @@ +/** + * @file TAMakerChannelDistanceAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelDistance/TAMakerChannelDistanceAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TAMakerChannelDistanceAlgorithm" + +namespace triggeralgs { + +void +TAMakerChannelDistanceAlgorithm::set_new_ta(const TriggerPrimitive& input_tp) +{ + m_current_ta = TriggerActivity(); + m_current_ta.inputs.push_back(input_tp); + m_current_lower_bound = input_tp.channel - m_max_channel_distance; + m_current_upper_bound = input_tp.channel + m_max_channel_distance; + return; +} + +void +TAMakerChannelDistanceAlgorithm::process(const TriggerPrimitive& input_tp, + std::vector& output_tas) +{ + + // Start a new TA if not already going. + if (m_current_ta.inputs.empty()) { + set_new_ta(input_tp); + return; + } + + // Check to close the TA based on time. + if (input_tp.time_start - m_current_ta.inputs.front().time_start > m_window_length) { + // Check to block the TA based on min TPs. + if (m_current_ta.inputs.size() >= m_min_tps) { + set_ta_attributes(); + output_tas.push_back(m_current_ta); + } + set_new_ta(input_tp); + return; + } + + // Check to skip the TP if it's outside the current channel bounds. + if (input_tp.channel > m_current_upper_bound || input_tp.channel < m_current_lower_bound) + return; + + m_current_ta.inputs.push_back(input_tp); + m_current_lower_bound = std::min(m_current_lower_bound, channel_diff_t(input_tp.channel) - m_max_channel_distance); + m_current_upper_bound = std::max(m_current_upper_bound, channel_diff_t(input_tp.channel) + m_max_channel_distance); +} + +void +TAMakerChannelDistanceAlgorithm::configure(const nlohmann::json& config) +{ + TriggerActivityMaker::configure(config); + + if (config.contains("min_tps")) + m_min_tps = config["min_tps"]; + if (config.contains("window_length")) + m_window_length = config["window_length"]; + if (config.contains("max_channel_distance")) + m_max_channel_distance = config["max_channel_distance"]; + + return; +} + +void +TAMakerChannelDistanceAlgorithm::set_ta_attributes() +{ + TriggerPrimitive first_tp = m_current_ta.inputs.front(); + TriggerPrimitive last_tp = m_current_ta.inputs.back(); + + m_current_ta.channel_start = first_tp.channel; + m_current_ta.channel_end = last_tp.channel; + + m_current_ta.time_start = first_tp.time_start; + m_current_ta.time_end = last_tp.time_start; + + m_current_ta.detid = first_tp.detid; + + m_current_ta.algorithm = TriggerActivity::Algorithm::kChannelDistance; + m_current_ta.type = TriggerActivity::Type::kTPC; + + m_current_ta.adc_peak = 0; + for (const TriggerPrimitive& tp : m_current_ta.inputs) { + m_current_ta.adc_integral += tp.adc_integral; + if (tp.adc_peak <= m_current_ta.adc_peak) + continue; + m_current_ta.adc_peak = tp.adc_peak; + m_current_ta.channel_peak = tp.channel; + m_current_ta.time_peak = tp.samples_to_peak * 32 + tp.time_start; // FIXME: Replace STP to `time_peak` conversion. + } + m_current_ta.time_activity = m_current_ta.time_peak; +} + +// Register algo in TA Factory +REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerChannelDistanceAlgorithm) + +} // namespace triggeralgs diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerDBSCANAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerDBSCANAlgorithm.cpp new file mode 100644 index 0000000..6672b1f --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerDBSCANAlgorithm.cpp @@ -0,0 +1,91 @@ +/** + * @file TAMakerDBSCANAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/TAMakerDBSCANAlgorithm.hpp" +#include "dbscan/Point.hpp" + +#include "TRACE/trace.h" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Types.hpp" +#include +#include +#define TRACE_NAME "TAMakerDBSCANAlgorithm" + +#include + +using namespace triggeralgs; + +using Logging::TLVL_DEBUG_LOW; + +void +TAMakerDBSCANAlgorithm::process(const TriggerPrimitive& input_tp, std::vector& output_ta) +{ + if(input_tp.time_start < m_prev_timestamp){ + TLOG_DEBUG(TLVL_DEBUG_LOW) << "[TAM:DBS] Out-of-order TPs: prev " << m_prev_timestamp << ", current " << input_tp.time_start; + return; + } + + m_dbscan_clusters.clear(); + m_dbscan->add_primitive(input_tp, &m_dbscan_clusters); + + uint64_t t0=m_dbscan->get_first_prim_time(); + + for(auto const& cluster : m_dbscan_clusters){ + auto& ta=output_ta.emplace_back(); + + ta.time_start = std::numeric_limits::max(); + ta.time_end = 0; + ta.channel_start = std::numeric_limits::max(); + ta.channel_end = 0; + ta.adc_integral = 0; + + for(auto const& hit : cluster.hits){ + auto const& prim=hit->primitive; + + ta.inputs.push_back(prim); + + ta.time_start = std::min(prim.time_start, ta.time_start); + ta.time_end = std::max(prim.time_start + prim.samples_over_threshold * 32, ta.time_end); // FIXME: Replace the hard-coded SOT to TOT scaling. + + ta.channel_start = std::min(channel_t(prim.channel), ta.channel_start); + ta.channel_end = std::max(channel_t(prim.channel), ta.channel_end); + + ta.adc_integral += prim.adc_integral; + + ta.detid = prim.detid; + if (prim.adc_peak > ta.adc_peak) { + ta.adc_peak = prim.adc_peak; + ta.channel_peak = prim.channel; + ta.time_peak = prim.samples_to_peak * 32 + prim.time_start; // FIXME: Replace hard-coded STP to `time_peak` conversion. + } + } + ta.time_activity = ta.time_peak; + + ta.type = TriggerActivity::Type::kTPC; + ta.algorithm = TriggerActivity::Algorithm::kDBSCAN; + } + + m_dbscan->trim_hits(); +} + +void +TAMakerDBSCANAlgorithm::configure(const nlohmann::json& config) +{ + TriggerActivityMaker::configure(config); + + if (config.is_object()) + { + if (config.contains("min_pts")) + m_min_pts = config["min_pts"]; + if (config.contains("eps")) + m_eps = config["eps"]; + } + m_dbscan=std::make_unique(m_eps, m_min_pts, 10000); +} + +// Register algo in TA Factory +REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerDBSCANAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerHorizontalMuonAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerHorizontalMuonAlgorithm.cpp new file mode 100644 index 0000000..505d6ea --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerHorizontalMuonAlgorithm.cpp @@ -0,0 +1,338 @@ +/** + * @file TAMakerHorizontalMuonAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/TAMakerHorizontalMuonAlgorithm.hpp" +#include "TRACE/trace.h" +#define TRACE_NAME "TAMakerHorizontalMuonAlgorithm" +#include +#include +#include + +using namespace triggeralgs; + +using Logging::TLVL_DEBUG_ALL; +using Logging::TLVL_DEBUG_MEDIUM; + +void +TAMakerHorizontalMuonAlgorithm::process(const TriggerPrimitive& input_tp, + std::vector& output_ta) +{ + + uint16_t adjacency; + + // Add useful info about recived TPs here for FW and SW TPG guys. + if (m_print_tp_info) { + TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TAM:HM] TP Start Time: " << input_tp.time_start + << ", TP ADC Sum: " << input_tp.adc_integral + << ", TP SOT: " << input_tp.samples_over_threshold << ", TP ADC Peak: " << input_tp.adc_peak + << ", TP Offline Channel ID: " << input_tp.channel; + TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TAM:HM] Adjacency of current window is: " << check_adjacency(); + } + + // 0) FIRST TP ===================================================================== + // The first time process() is called, reset the window object. + if (m_current_window.is_empty()) { + m_current_window.reset(input_tp); + return; + } + + // If the difference between the current TP's start time and the start of the window + // is less than the specified window size, add the TP to the window. + if ((input_tp.time_start - m_current_window.time_start) < m_window_length) { + m_current_window.add(input_tp); + } + + // 1) ADC THRESHOLD EXCEEDED ======================================================= + // If the addition of the current TP to the window would make it longer specified + // window length, don't add it but check whether the ADC integral if the existing + // window is above the configured threshold. If it is, and we are triggering on ADC, + // make a TA and start a fresh window with the current TP. + else if (m_current_window.adc_integral > m_adc_threshold && m_trigger_on_adc) { + + auto ta = construct_ta(); + + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TA:HM]: Emitting ADC threshold trigger with " << m_current_window.adc_integral + << " window ADC integral. ta.time_start=" << ta.time_start + << " ta.time_end=" << ta.time_end; + + output_ta.push_back(ta); + m_current_window.reset(input_tp); + } + + // 2) MULTIPLICITY - N UNQIUE CHANNELS EXCEEDED ===================================== + // If the addition of the current TP to the window would make it longer than the + // specified window length, don't add it but check whether the number of hit channels + // in the existing window is above the specified threshold. If it is, and we are triggering + // on channel multiplicity, make a TA and start a fresh window with the current TP. + else if (m_current_window.n_channels_hit() > m_n_channels_threshold && m_trigger_on_n_channels) { + + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TAM:HM] Emitting multiplicity trigger with " + << m_current_window.n_channels_hit() << " unique channels hit."; + + output_ta.push_back(construct_ta()); + m_current_window.reset(input_tp); + } + + // 3) ADJACENCY THRESHOLD EXCEEDED ================================================== + // If the addition of the current TP to the window would make it longer than the + // specified window length, don't add it but check whether the adjacency of the + // current window exceeds the configured threshold. If it does, and we are triggering + // on adjacency, then create a TA and reset the window with the new/current TP. + else if ((adjacency = check_adjacency()) > m_adjacency_threshold && m_trigger_on_adjacency) { + + //for (auto tp : m_current_window.inputs){ dump_tp(tp); } + + // Check for a new maximum, display the largest seen adjacency in the log. + // uint16_t adjacency = check_adjacency(); + if (adjacency > m_max_adjacency) { + m_max_adjacency = adjacency; + } + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TAM:HM] Emitting track and multiplicity TA with adjacency " + << check_adjacency() << " and multiplicity " << m_current_window.n_channels_hit() + << ". The ADC integral of this TA is " << m_current_window.adc_integral + << " and the largest longest track seen so far is " << m_max_adjacency; + + output_ta.push_back(construct_ta()); + m_current_window.reset(input_tp); + } + + // Temporary triggering logic for Adam's large SOT TPs. Trigger on very large SOT TPs. + else if (m_trigger_on_sot && input_tp.samples_over_threshold > m_sot_threshold) { + + // If the incoming TP has a large time over threshold, we might have a cluster of + // interesting physics activity surrounding it. Trigger on that. + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TAM:HM] Emitting a TA due to a TP with a very large samples over threshold: " + << input_tp.samples_over_threshold << " ticks and offline channel: " << input_tp.channel + << ", where the ADC integral of that TP is " << input_tp.adc_integral; + output_ta.push_back(construct_ta()); + m_current_window.reset(input_tp); + } + + // 4) Otherwise, slide the window along using the current TP. + else { + m_current_window.move(input_tp, m_window_length); + } + + return; +} + +void +TAMakerHorizontalMuonAlgorithm::configure(const nlohmann::json& config) +{ + TriggerActivityMaker::configure(config); + + if (config.is_object()) { + if (config.contains("trigger_on_adc")) + m_trigger_on_adc = config["trigger_on_adc"]; + if (config.contains("trigger_on_n_channels")) + m_trigger_on_n_channels = config["trigger_on_n_channels"]; + if (config.contains("adc_threshold")) + m_adc_threshold = config["adc_threshold"]; + if (config.contains("n_channels_threshold")) + m_n_channels_threshold = config["n_channels_threshold"]; + if (config.contains("window_length")) + m_window_length = config["window_length"]; + if (config.contains("trigger_on_adjacency")) + m_trigger_on_adjacency = config["trigger_on_adjacency"]; + if (config.contains("adjacency_tolerance")) + m_adj_tolerance = config["adjacency_tolerance"]; + if (config.contains("adjacency_threshold")) + m_adjacency_threshold = config["adjacency_threshold"]; + if (config.contains("print_tp_info")) + m_print_tp_info = config["print_tp_info"]; + if (config.contains("trigger_on_sot")) + m_trigger_on_sot = config["trigger_on_sot"]; + if (config.contains("sot_threshold")) + m_sot_threshold = config["sot_threshold"]; + } + +} + +TriggerActivity +TAMakerHorizontalMuonAlgorithm::construct_ta() const +{ + + TriggerActivity ta; + + TriggerPrimitive last_tp = m_current_window.inputs.back(); + + ta.time_start = last_tp.time_start; + ta.time_end = last_tp.time_start + last_tp.samples_over_threshold * 32; // FIXME: Replace the hard-coded SOT to TOT scaling. + ta.time_peak = last_tp.samples_to_peak * 32 + last_tp.time_start; // FIXME: Replace STP to `time_peak` conversion. + ta.time_activity = ta.time_peak; + ta.channel_start = last_tp.channel; + ta.channel_end = last_tp.channel; + ta.channel_peak = last_tp.channel; + ta.adc_integral = m_current_window.adc_integral; + ta.adc_peak = last_tp.adc_integral; + ta.detid = last_tp.detid; + ta.type = TriggerActivity::Type::kTPC; + ta.algorithm = TriggerActivity::Algorithm::kHorizontalMuon; + ta.inputs = m_current_window.inputs; + + for( const auto& tp : ta.inputs ) { + ta.time_start = std::min(ta.time_start, tp.time_start); + ta.time_end = std::max(ta.time_end, tp.time_start + tp.samples_over_threshold * 32); // FIXME: Replace the hard-coded SOT to TOT scaling. + ta.channel_start = std::min(ta.channel_start, channel_t(tp.channel)); + ta.channel_end = std::max(ta.channel_end, channel_t(tp.channel)); + if (tp.adc_peak > ta.adc_peak) { + ta.time_peak = tp.samples_to_peak * 32 + tp.time_start; // FIXME: Replace STP to `time_peak` conversion. + ta.adc_peak = tp.adc_peak; + ta.channel_peak = tp.channel; + } + } + + return ta; +} + +uint16_t +TAMakerHorizontalMuonAlgorithm::check_adjacency() const +{ + // This function returns the adjacency value for the current window, where adjacency + // is defined as the maximum number of consecutive wires containing hits. It accepts + // a configurable tolerance paramter, which allows up to adj_tolerance missing hits + // on adjacent wires before restarting the adjacency count. The maximum gap is 4 which + // comes from tuning on December 2021 coldbox data, and June 2022 coldbox runs. + + uint16_t adj = 1; // Initialise adjacency, 1 for the first wire. + uint16_t max = 0; // Maximum adjacency of window, which this function returns + unsigned int channel = 0; // Current channel ID + unsigned int next_channel = 0; // Next channel ID + unsigned int next = 0; // The next position in the hit channels vector + unsigned int tol_count = 0; // Tolerance count, should not pass adj_tolerance + + // Generate a channelID ordered list of hit channels for this window + std::vector chanList; + for (auto tp : m_current_window.inputs) { + chanList.push_back(channel_t(tp.channel)); + } + std::sort(chanList.begin(), chanList.end()); + + // ADAJACENCY LOGIC ==================================================================== + // ===================================================================================== + // Adjcancency Tolerance = Number of times prepared to skip missed hits before resetting + // the adjacency count. This accounts for things like dead channels / missed TPs. The + // maximum gap is 4 which comes from tuning on December 2021 coldbox data, and June 2022 + // coldbox runs. + for (int i = 0; i < chanList.size(); ++i) { + + next = (i + 1) % chanList.size(); // Loops back when outside of channel list range + channel = chanList.at(i); + next_channel = chanList.at(next); // Next channel with a hit + + // End of vector condition. + if (next_channel == 0) { + next_channel = channel - 1; + } + + // Skip same channel hits. + if (next_channel == channel) { + continue; + } + + // If next hit is on next channel, increment the adjacency count. + else if (next_channel == channel + 1) { + ++adj; + } + + // If next channel is not on the next hit, but the 'second next', increase adjacency + // but also tally up with the tolerance counter. + else if (((next_channel == channel + 2) || (next_channel == channel + 3) || (next_channel == channel + 4) || + (next_channel == channel + 5)) && + (tol_count < m_adj_tolerance)) { + ++adj; + for (int i = 0; i < next_channel - channel; ++i) { + ++tol_count; + } + } + + // If next hit isn't within reach, end the adjacency count and check for a new max. + // Reset variables for next iteration. + else { + if (adj > max) { + max = adj; + } + adj = 1; + tol_count = 0; + } + } + + return max; +} + +// ===================================================================================== +// Functions below this line are for debugging purposes. +// ===================================================================================== +void +TAMakerHorizontalMuonAlgorithm::add_window_to_record(TPWindow window) +{ + m_window_record.push_back(window); + return; +} + +// Function to dump the details of the TA window currently on record +void +TAMakerHorizontalMuonAlgorithm::dump_window_record() +{ + std::ofstream outfile; + outfile.open("window_record_tam.csv", std::ios_base::app); + + for (auto window : m_window_record) { + outfile << window.time_start << ","; + outfile << window.inputs.back().time_start << ","; + outfile << window.inputs.back().time_start - window.time_start << ","; + outfile << window.adc_integral << ","; + outfile << window.n_channels_hit() << ","; // Number of unique channels with hits + outfile << window.inputs.size() << ","; // Number of TPs in TPWindow + outfile << window.inputs.back().channel << ","; // Last TP Channel ID + outfile << window.inputs.front().channel << ","; // First TP Channel ID + outfile << check_adjacency() << ","; // New adjacency value for the window + outfile << check_sot() << std::endl; // Summed window SOT + } + + outfile.close(); + m_window_record.clear(); + + return; +} + +// Function to add current TP details to a text file for testing and debugging. +void +TAMakerHorizontalMuonAlgorithm::dump_tp(TriggerPrimitive const& input_tp) +{ + std::ofstream outfile; + outfile.open("coldbox_tps.txt", std::ios_base::app); + + // Output relevant TP information to file + outfile << input_tp.time_start << " "; + outfile << input_tp.samples_over_threshold << " "; // 50MHz ticks + outfile << input_tp.samples_to_peak << " "; + outfile << input_tp.channel << " "; // Offline channel ID + outfile << input_tp.adc_integral << " "; + outfile << input_tp.adc_peak << " "; + outfile << input_tp.detid << " "; // Det ID - Identifies detector element + outfile.close(); + + return; +} + +int +TAMakerHorizontalMuonAlgorithm::check_sot() const +{ + // Here, we just want to sum up all the sot values for each TP within window, + // and return this sot of the window. + int window_sot = 0; + for (auto tp : m_current_window.inputs) { + window_sot += tp.samples_over_threshold; + } + + return window_sot; +} + +// Register algo in TA Factory +REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerHorizontalMuonAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerMichelElectronAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerMichelElectronAlgorithm.cpp new file mode 100644 index 0000000..4283a36 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerMichelElectronAlgorithm.cpp @@ -0,0 +1,382 @@ +/** + * @file TAMakerMichelElectronAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/TAMakerMichelElectronAlgorithm.hpp" +#include "TRACE/trace.h" +#define TRACE_NAME "TAMakerMichelElectronAlgorithm" +#include +#include + +using namespace triggeralgs; + +using Logging::TLVL_DEBUG_MEDIUM; + +void +TAMakerMichelElectronAlgorithm::process(const TriggerPrimitive& input_tp, + std::vector& output_ta) +{ + + // The first time operator() is called, reset the window object. + if (m_current_window.is_empty()) { + m_current_window.reset(input_tp); + m_primitive_count++; + return; + } + + // If the difference between the current TP's start time and the start of the window + // is less than the specified window size, add the TP to the window. + if ((input_tp.time_start - m_current_window.time_start) < m_window_length) { + m_current_window.add(input_tp); + } + + // Check Michel Candidate ======================================================== + // We've filled the window, now require a sufficient length track AND that the track + // has a potential Bragg P, and then a kink. + else if (longest_activity().size() > m_adjacency_threshold) { + + + // We have a good length acitivity, now search for Bragg peak and kinks + std::vector trackHits = longest_activity(); + + if (check_bragg_peak(trackHits)){ + if (check_kinks(trackHits)){ + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TAM:ME] Emitting a trigger for candidate Michel event."; + output_ta.push_back(construct_ta()); + m_current_window.reset(input_tp); + } // Kinks + } // Bragg peak + + } + + // Otherwise, slide the window along using the current TP. + else { + m_current_window.move(input_tp, m_window_length); + } + + m_primitive_count++; + return; +} + +void +TAMakerMichelElectronAlgorithm::configure(const nlohmann::json& config) +{ + TriggerActivityMaker::configure(config); + + // FIX ME: Use some schema here. Also can't work out how to pass booleans. + if (config.is_object()) { + if (config.contains("window_length")) + m_window_length = config["window_length"]; + if (config.contains("adjacency_tolerance")) + m_adj_tolerance = config["adjacency_tolerance"]; + if (config.contains("adjacency_threshold")) + m_adjacency_threshold = config["adjacency_threshold"]; + } + +} + +TriggerActivity +TAMakerMichelElectronAlgorithm::construct_ta() const +{ + + TriggerPrimitive latest_tp_in_window = m_current_window.inputs.back(); + + TriggerActivity ta; + ta.time_start = m_current_window.time_start; + ta.time_end = latest_tp_in_window.time_start + latest_tp_in_window.samples_over_threshold * 32; // FIXME: Replace the hard-coded SOT to TOT scaling. + ta.time_peak = latest_tp_in_window.samples_to_peak * 32 + latest_tp_in_window.time_start; // FIXME: Replace STP to `time_peak` conversion. + ta.time_activity = ta.time_peak; + ta.channel_start = latest_tp_in_window.channel; + ta.channel_end = latest_tp_in_window.channel; + ta.channel_peak = latest_tp_in_window.channel; + ta.adc_integral = m_current_window.adc_integral; + ta.adc_peak = latest_tp_in_window.adc_peak; + ta.detid = latest_tp_in_window.detid; + ta.type = TriggerActivity::Type::kTPC; + ta.algorithm = TriggerActivity::Algorithm::kMichelElectron; + ta.inputs = m_current_window.inputs; + + return ta; +} + +std::vector +TAMakerMichelElectronAlgorithm::longest_activity() const +{ + // This function attempts to return a vector of hits that correspond to the longest + // piece of activity in the current window. The logic follows that from the HMA + // check_adjacency() function and further details can be found there. + std::vector trackHits; + std::vector finalHits; // The vector of track hits, which we return + + uint16_t adj = 1; // Initialise adjacency, 1 for the first wire. + uint16_t max = 0; + unsigned int channel = 0; // Current channel ID + unsigned int next_channel = 0; // Next channel ID + unsigned int next = 0; // The next position in the hit channels vector + unsigned int tol_count = 0; // Tolerance count, should not pass adj_tolerance + + // Generate a channelID ordered list of hit channels for this window + std::vector hitList; + for (auto tp : m_current_window.inputs) { + hitList.push_back(tp); + } + std::sort(hitList.begin(), hitList.end(), [](TriggerPrimitive a, TriggerPrimitive b) + { return a.channel < b.channel; }); + + // ADAJACENCY LOGIC ==================================================================== + // ===================================================================================== + // Adjcancency Tolerance = Number of times prepared to skip missed hits before resetting + // the adjacency count. This accounts for things like dead channels / missed TPs. The + // maximum gap is 4 which comes from tuning on December 2021 coldbox data, and June 2022 + // coldbox runs. + for (int i = 0; i < hitList.size(); ++i) { + + next = (i + 1) % hitList.size(); // Loops back when outside of channel list range + channel = hitList.at(i).channel; + next_channel = hitList.at(next).channel; // Next channel with a hit + + if (trackHits.size() == 0 ){ trackHits.push_back(hitList.at(i)); } + + // End of vector condition. + if (next_channel == 0) { next_channel = channel - 1; } + + // Skip same channel hits for adjacency counting, but add to the track! + if (next_channel == channel) { + trackHits.push_back(hitList.at(next)); + continue; } + + // If next hit is on next channel, increment the adjacency count. + else if (next_channel == channel + 1){ + trackHits.push_back(hitList.at(next)); + ++adj; } + + // If next channel is not on the next hit, but the 'second next', increase adjacency + // but also tally up with the tolerance counter. + else if (((next_channel == channel + 2) || (next_channel == channel + 3) || + (next_channel == channel + 4) || (next_channel == channel + 5)) + && (tol_count < m_adj_tolerance)) { + trackHits.push_back(hitList.at(next)); + ++adj; + for (int i = 0 ; i < next_channel-channel ; ++i){ ++tol_count; } + } + + // If next hit isn't within reach, end the adjacency count and check for a new max. + // Reset variables for next iteration. + else { + if (adj > max) { + max = adj; + finalHits.clear(); // Clear previous track + for (auto h : trackHits){ + finalHits.push_back(h); + } + } + adj = 1; + tol_count = 0; + trackHits.clear(); + } + } + + return finalHits; +} + + +// Function that tries to identify a Bragg peak via a running +// mean average of the ADC values. We use the running mean as it's less susceptible to +// spikes of activity that might trick the algorithm. We establish a baseline, then +// count up clusters of charge deposition above that baseline. If the largest is at +// one of the ends of that collection, signal a potential Bragg peak. +bool +TAMakerMichelElectronAlgorithm::check_bragg_peak(std::vector trackHits) +{ + bool bragg = false; + std::vector adc_means_list; + uint16_t convolve_value = 6; + + // Loop over hits that correspond to high adjacency activity + for (uint16_t i = 0; i < trackHits.size(); ++i){ + float adc_sum = 0; + float adc_mean = 0; + + // Calculate running ADC mean of this track + for (uint16_t j = i; j < i+convolve_value; ++j){ + int hit = (j) % trackHits.size(); + adc_sum += trackHits.at(hit).adc_integral; + } + + adc_mean = adc_sum / convolve_value; + adc_means_list.push_back(adc_mean); + adc_sum = 0; + } + + // We now have a list of convolved adc means. + float ped = std::accumulate(adc_means_list.begin(), adc_means_list.end(), 0.0) / adc_means_list.size(); + float charge = 0; + std::vector charge_dumps; + + // Now go through the list, picking up clusters of charge above the baseline/ped + for (auto a : adc_means_list){ + if (a > ped){ + charge += a; + } + else if( a < ped && charge !=0 ){ + charge_dumps.push_back(charge); + charge = 0; + } + } + + // If the maximum of that list of charge dumps is near(at?) either end of it + float max_charge = *max_element(charge_dumps.begin(), charge_dumps.end()); + if(max_charge == charge_dumps.front() || max_charge == charge_dumps.back()){ bragg=true; } + + return bragg; + } + +bool +TAMakerMichelElectronAlgorithm::check_kinks(std::vector finalHits) +{ + bool kinks = false; // We actually required two kinks in the coldbox, the michel kink and the wes kink + std::vector runningGradient; + std::vector runningMeanGradient; + + // Choice to be made here. Do we want to scane in collection (z) or time (x) direction when calculating gradient between hits. I + // would say if we have already made the request to pass a track of length specific threshold which is longer than the drift + // direction for the coldbox, it makes sense to scan across channels a little more. + std::sort(finalHits.begin(), finalHits.end(), [](TriggerPrimitive a, TriggerPrimitive b) { return a.channel < b.channel; }); + + // Populate the runningGradient with the track hits. Do this between ith and i+kth TPs, to small scale fluctuations of the track + // Yet k should be kept small, so that enough gradient information is preserved at the end of the track to identify kinks + for (int i=0 ; i < finalHits.size()-2; i++){ + + // Skip same channel hits or if the start times are the same - no div by zero! + if (finalHits.at(i+2).channel == finalHits.at(i).channel || (finalHits.at(i+2).time_start == finalHits.at(i).time_start) ) { continue; } + + // Check that the next TP is closeby; enough in space and time directions so as to avoid obtaining a gradient value from + // same channel hits at large time difference or vice versa due to kink topology or showers. Clearly we shouldn't be very far in + // channel number, but since we might later try to do this check in the time direction, leave the condition in. + int diff = finalHits.at(i+2).time_start - finalHits.at(i).time_start; + if((std::abs(diff) > 1000) || ((std::abs(channel_diff_t(finalHits.at(i+2).channel) - channel_diff_t(finalHits.at(i).channel)) > 6))) { continue; } + + // Gradient is just change in z (collection) over change in x (drift). x is admitedly roughly converted from + // hit start time, but I don't think diffusion effects are a huge concern over 20cm. Using mm for readability/visualisation + float dz = (finalHits.at(i+2).channel - finalHits.at(i).channel)*4.67; // Change in collection wire z to separation in mm + long long int dt = finalHits.at(i+2).time_start - finalHits.at(i).time_start; + float dx = dt*0.028; // Change time to separation in x mm + float g = dz/dx; + + runningGradient.push_back(g); + } + + // Require a decent length of the gradients vector. Otherwise some adjacent events are showers and the conditions above mean + // we don't get enough entries. In essence, this provides some confidence that it's track-like rather than shower-like. Which + // is what we want for a Michel event. + if ( runningGradient.size() > 10 ){ + + // Now lets take a running mean of the gradients between TPs, less susceptible to wild changes due to deltas/etc + for(int g=0 ; g < runningGradient.size()-1 ; g++){ + float gsum = runningGradient.at(g) + runningGradient.at(g+1); + runningMeanGradient.push_back(gsum/2); + } + + // We have a list of gradients, now just demand that the two ends have gradients that differ significantly + // from the mean gradient of the activity at both ends. This aims to pick out wesKinks and michelKinks + if(runningMeanGradient.size() > 10 ){ + + float mean = (std::abs(std::accumulate(runningMeanGradient.begin(), runningMeanGradient.end(), 0.0)))/(runningMeanGradient.size()); + + // If you're testing on simulation or december data, you won't see the wes kink, so use an || instead of && + if((std::abs(runningMeanGradient.front()) + mean > 2.5*mean) || ((std::abs(runningMeanGradient.back() + mean)) > 2.5*mean)){ kinks=true; } + } + } + + return kinks; +} + +// =============================================================================================== +// =============================================================================================== +// Functions below this line are for debugging purposes. +// =============================================================================================== + +void +TAMakerMichelElectronAlgorithm::add_window_to_record(Window window) +{ + m_window_record.push_back(window); + return; +} + + +// Function to dump the details of the TA window currently on record +void +TAMakerMichelElectronAlgorithm::dump_window_record() +{ + // FIX ME: Need to index this outfile in the name by detid or something similar. + std::ofstream outfile; + outfile.open("window_record_tam.csv", std::ios_base::app); + + for (auto window : m_window_record) { + outfile << window.time_start << ","; + outfile << window.inputs.back().time_start << ","; + outfile << window.inputs.back().time_start - window.time_start << ","; // window_length - from TP start times + outfile << window.adc_integral << ","; + outfile << window.n_channels_hit() << ","; // Number of unique channels with hits + outfile << window.inputs.size() << ","; // Number of TPs in Window + outfile << window.inputs.back().channel << ","; // Last TP Channel ID + outfile << window.inputs.front().channel << ","; // First TP Channel ID + outfile << longest_activity().size() << std::endl; // New adjacency value for the window + } + + outfile.close(); + + m_window_record.clear(); + + return; +} + +// Function to add current TP details to a text file for testing and debugging. +void +TAMakerMichelElectronAlgorithm::dump_tp(TriggerPrimitive const& input_tp) +{ + std::ofstream outfile; + outfile.open("coldbox_tps.txt", std::ios_base::app); + + // Output relevant TP information to file + outfile << input_tp.time_start << " "; // Start time of TP + outfile << input_tp.samples_over_threshold << " "; // in multiples of 25 + outfile << input_tp.samples_to_peak << " "; // + outfile << input_tp.channel << " "; // Offline channel ID + outfile << input_tp.adc_integral << " "; // ADC Sum + outfile << input_tp.adc_peak << " "; // ADC Peak Value + outfile << input_tp.detid << " "; // Det ID - Identifies detector element, APA or PDS part etc... + outfile.close(); + + return; +} + +/* +void +TAMakerMichelElectronAlgorithm::flush(timestamp_t, std::vector& output_ta) +{ + // Check the status of the current window, construct TA if conditions are met. Regardless + // of whether the conditions are met, reset the window. + if(m_current_window.adc_integral > m_adc_threshold && m_trigger_on_adc){ + //else if(m_current_window.adc_integral > m_conf.adc_threshold && m_conf.trigger_on_adc){ + //TLOG_DEBUG(TRACE_NAME) << "ADC integral in window is greater than specified threshold."; + output_ta.push_back(construct_ta()); + } + else if(m_current_window.n_channels_hit() > m_n_channels_threshold && m_trigger_on_n_channels){ + //else if(m_current_window.n_channels_hit() > m_conf.n_channels_threshold && m_conf.trigger_on_n_channels){ + //TLOG_DEBUG(TRACE_NAME) << "Number of channels hit in the window is greater than specified threshold."; + output_ta.push_back(construct_ta()); + } + + //TLOG_DEBUG(TRACE_NAME) << "Clearing the current window, on the arrival of the next input_tp, the window will be +reset."; m_current_window.clear(); + + return; +}*/ + +// Register algo in TA Factory +REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerMichelElectronAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerPlaneCoincidenceAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerPlaneCoincidenceAlgorithm.cpp new file mode 100644 index 0000000..43af587 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerPlaneCoincidenceAlgorithm.cpp @@ -0,0 +1,273 @@ +/** + * @file TAMakerPlaneCoincidenceAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/TAMakerPlaneCoincidenceAlgorithm.hpp" +#include "TRACE/trace.h" +#define TRACE_NAME "TAMakerPlaneCoincidenceAlgorithm" +#include + +using namespace triggeralgs; + +using Logging::TLVL_DEBUG_MEDIUM; + +void +TAMakerPlaneCoincidenceAlgorithm::process(const TriggerPrimitive& input_tp, std::vector& output_ta) +{ + + // Get the plane from which this hit arrived: + // U (induction) = 0, Y (induction) = 1, Z (collection) = 2, unconnected channel = 9999 + uint plane = channelMap->get_plane_from_offline_channel(input_tp.channel); + bool isU = plane == 0; // Induction1 = U + bool isY = plane == 1; // Induction2 = Y + bool isZ = plane == 2; // Collection = Z + + // The first time operator() is called, reset the window object(s). + if (m_induction1_window.is_empty() && isU) { m_induction1_window.reset(input_tp); m_primitive_count++; return; } + if (m_induction2_window.is_empty() && isY) { m_induction2_window.reset(input_tp); m_primitive_count++; return; } + if (m_collection_window.is_empty() && isZ) { m_collection_window.reset(input_tp); m_primitive_count++; return; } + + // If the difference between the current TP's start time and the start of the window + // is less than the specified window size, add the TP to the corresponding window. + if (isU && (input_tp.time_start - m_induction1_window.time_start) < m_window_length) m_induction1_window.add(input_tp); + if (isY && (input_tp.time_start - m_induction2_window.time_start) < m_window_length) m_induction2_window.add(input_tp); + if (isZ && (input_tp.time_start - m_collection_window.time_start) < m_window_length) m_collection_window.add(input_tp); + + // ISSUE - We are checking the collection plane window too early: Every time we are NOT receiving a collection plane + // TP, we're checking the trigger conditions. Fix this immediately and rerun trigger runs to test. + + // =================================================================================== + // Below this line, we begin our hierarchy of checks for a low energy event, + // taking advantage of the newly gained induction hits window. + // =================================================================================== + + // Our windows have ADC Sum, Time Over Threshold, Multiplicity & Adjacency properties. + // Take advantage of these to screen the activities passed to more involved checks. + + // 1) REQUIRE ADC SPIKE FROM INDUCTION AND CHECK ADJACENCY =========================== + // We're looking for a localised spike of ADC (short time window) and then a short + // adjacency corresponding to an electron track/shower. + + // ISSUE - We are checking the collection plane window too early and too frequently probably: + // Every time we are NOT receiving a collection plane TP, we're checking the trigger conditions. + // Fix this immediately and rerun trigger runs to test. + // Introduce bool to check for collection window completeness: + bool collectionComplete = (input_tp.time_start - m_collection_window.time_start) > m_window_length; + // Then require that the collection window be complete in the adjacency checks + if (!collectionComplete) { } // Do nothing + else if (collectionComplete && (m_induction1_window.adc_integral + m_induction2_window.adc_integral + m_collection_window.adc_integral) + > m_adc_threshold && check_adjacency(m_collection_window) >= m_adjacency_threshold){ + + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TAM:PC] Emitting low energy trigger with " << m_induction1_window.adc_integral << " U " + << m_induction2_window.adc_integral << " Y induction ADC sums and " + << check_adjacency(m_collection_window) << " adjacent collection hits."; + + // Initial studies - output the TPs of the collection plane window that caused this trigger + add_window_to_record(m_collection_window); + dump_window_record(); + m_window_record.clear(); + + // Initial studies - Also dump the TPs that have contributed to this TA decision + for(auto tp : m_collection_window.inputs) dump_tp(tp); + + // We have fulfilled our trigger condition, construct a TA and reset/flush the windows + // to ensure they're all in the same "time zone"! + output_ta.push_back(construct_ta(m_collection_window)); + if (isZ) m_collection_window.reset(input_tp); + else m_collection_window.clear(); + if (isU) m_induction1_window.reset(input_tp); + else m_induction1_window.clear(); + if (isY) m_induction2_window.reset(input_tp); + else m_induction2_window.clear(); + } + + // Otherwise, slide the relevant window along using the current TP. + else { + if (isU) m_induction1_window.move(input_tp, m_window_length); + else if (isY) m_induction2_window.move(input_tp, m_window_length); + else if (isZ) m_collection_window.move(input_tp, m_window_length); + } + m_primitive_count++; + + return; +} + +void +TAMakerPlaneCoincidenceAlgorithm::configure(const nlohmann::json& config) +{ + TriggerActivityMaker::configure(config); + + if (config.is_object()) { + if (config.contains("adc_threshold")) + m_adc_threshold = config["adc_threshold"]; + if (config.contains("window_length")) + m_window_length = config["window_length"]; + if (config.contains("adjacency_tolerance")) + m_adj_tolerance = config["adjacency_tolerance"]; + if (config.contains("adjacency_threshold")) + m_adjacency_threshold = config["adjacency_threshold"]; + } + +} + +TriggerActivity +TAMakerPlaneCoincidenceAlgorithm::construct_ta(TPWindow m_current_window) const +{ + + TriggerPrimitive latest_tp_in_window = m_current_window.inputs.back(); + + TriggerActivity ta; + ta.time_start = m_current_window.time_start; + ta.time_end = latest_tp_in_window.time_start + latest_tp_in_window.samples_over_threshold * 32; // FIXME: Replace the hard-coded SOT to TOT scaling. + ta.time_peak = latest_tp_in_window.samples_to_peak * 32 + latest_tp_in_window.time_start; // FIXME: Replace hard-coded STP to `time_peak` conversion. + ta.time_activity = ta.time_peak; + ta.channel_start = latest_tp_in_window.channel; + ta.channel_end = latest_tp_in_window.channel; + ta.channel_peak = latest_tp_in_window.channel; + ta.adc_integral = m_current_window.adc_integral; + ta.adc_peak = latest_tp_in_window.adc_peak; + ta.detid = latest_tp_in_window.detid; + ta.type = TriggerActivity::Type::kTPC; + ta.algorithm = TriggerActivity::Algorithm::kPlaneCoincidence; + ta.inputs = m_current_window.inputs; + + return ta; +} + +uint16_t +TAMakerPlaneCoincidenceAlgorithm::check_adjacency(TPWindow window) const +{ + /* This function returns the adjacency value for the current window, where adjacency + * is defined as the maximum number of consecutive wires containing hits. It accepts + * a configurable tolerance paramter, which allows up to adj_tolerance missing hits + * on adjacent wires before restarting the adjacency count. */ + + uint16_t adj = 1; // Initialise adjacency, 1 for the first wire. + uint16_t max = 0; // Maximum adjacency of window, which this function returns + unsigned int channel = 0; // Current channel ID + unsigned int next_channel = 0; // Next channel ID + unsigned int next = 0; // The next position in the hit channels vector + unsigned int tol_count = 0; // Tolerance count, should not pass adj_tolerance + + /* Generate a channelID ordered list of hit channels for this window */ + std::vector chanList; + for (auto tp : window.inputs) { + chanList.push_back(tp.channel); + } + std::sort(chanList.begin(), chanList.end()); + + /* ADAJACENCY LOGIC ==================================================================== + * Adjcancency Tolerance = Number of times prepared to skip missed hits before resetting + * the adjacency count. This accounts for things like dead channels / missed TPs. */ + for (size_t i = 0; i < chanList.size(); ++i) { + + next = (i + 1) % chanList.size(); // Loops back when outside of channel list range + channel = chanList.at(i); + next_channel = chanList.at(next); // Next channel with a hit + + // End of vector condition. + if (next_channel == 0) { next_channel = channel - 1; } + + // Skip same channel hits. + if (next_channel == channel) { continue; } + + // If next hit is on next channel, increment the adjacency count. + else if (next_channel == channel + 1){ ++adj; } + + // If next channel is not on the next hit, but the 'second next', increase adjacency + // but also tally up with the tolerance counter. + else if ((next_channel == channel + 2 || next_channel == channel + 3) && (tol_count < m_adj_tolerance)) { + ++adj; + for (size_t i = 0 ; i < next_channel-channel ; ++i) ++tol_count; + } + + // If next hit isn't within reach, end the adjacency count and check for a new max. + // Reset variables for next iteration. + else { + if (adj > max) { max = adj; } + adj = 1; + tol_count = 0; + } + } + + return max; +} + +// ===================================================================================== +// Functions below this line are for debugging and performance study purposes. +// ===================================================================================== +void +TAMakerPlaneCoincidenceAlgorithm::add_window_to_record(TPWindow window) +{ + m_window_record.push_back(window); + return; +} + +// Function to dump the details of the TA window currently on record +void +TAMakerPlaneCoincidenceAlgorithm::dump_window_record() +{ + std::ofstream outfile; + outfile.open("window_record_tam.csv", std::ios_base::app); + + for (auto window : m_window_record) { + outfile << window.time_start << ","; + outfile << window.inputs.back().time_start << ","; + outfile << window.inputs.back().time_start - window.time_start << ","; + outfile << window.adc_integral << ","; + outfile << window.n_channels_hit() << ","; // Number of unique channels with hits + outfile << window.inputs.size() << ","; // Number of TPs in TPWindow + outfile << window.inputs.back().channel << ","; // Last TP Channel ID + outfile << window.inputs.back().time_start << ","; // Last TP start time + outfile << window.inputs.front().channel << ","; // First TP Channel ID + outfile << window.inputs.front().time_start << ","; // First TP start time + outfile << check_adjacency(window) << ","; // New adjacency value for the window + outfile << check_sot(window) << std::endl; // Summed window SOT + } + + outfile.close(); + m_window_record.clear(); + + return; +} + +// Function to add current TP details to a text file for testing and debugging. +void +TAMakerPlaneCoincidenceAlgorithm::dump_tp(TriggerPrimitive const& input_tp) +{ + std::ofstream outfile; + outfile.open("triggered_coldbox_tps.txt", std::ios_base::app); + + // Output relevant TP information to file + outfile << input_tp.time_start << " "; + outfile << input_tp.samples_over_threshold << " "; // 50MHz ticks + outfile << input_tp.samples_to_peak << " "; + outfile << input_tp.channel << " "; // Offline channel ID + outfile << input_tp.adc_integral << " "; + outfile << input_tp.adc_peak << " "; + outfile << input_tp.detid << " "; // Det ID - Identifies detector element + outfile.close(); + + return; +} + +int +TAMakerPlaneCoincidenceAlgorithm::check_sot(TPWindow m_current_window) const +{ + // Here, we just want to sum up all the sot values for each TP within window, + // and return this sot of the window. + int window_sot = 0; + for (auto tp : m_current_window.inputs) { + window_sot += tp.samples_over_threshold; + } + + return window_sot; +} + +// Regiser algo in TA Factory +REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerPlaneCoincidenceAlgorithm) +// END OF TA MAKER - LOW ENERGY EVENTS diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerPrescaleAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerPrescaleAlgorithm.cpp new file mode 100644 index 0000000..4eab32a --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerPrescaleAlgorithm.cpp @@ -0,0 +1,53 @@ +/** + * @file TAMakerPrescaleAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Prescale/TAMakerPrescaleAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TAMakerPrescaleAlgorithm" + +#include + +using namespace triggeralgs; + +using Logging::TLVL_DEBUG_MEDIUM; +using Logging::TLVL_IMPORTANT; + +void +TAMakerPrescaleAlgorithm::process(const TriggerPrimitive& input_tp, std::vector& output_ta) +{ + std::vector tp_list; + tp_list.push_back(input_tp); + + TriggerActivity ta; + ta.time_start = input_tp.time_start; + ta.time_end = input_tp.time_start + input_tp.samples_over_threshold * 32; // FIXME: Replace the hard-coded SOT to TOT scaling. + ta.time_peak = input_tp.samples_to_peak * 32 + input_tp.time_start; // FIXME: Replace STP to `time_peak` conversion. + ta.time_activity = 0; + ta.channel_start = input_tp.channel; + ta.channel_end = input_tp.channel; + ta.channel_peak = input_tp.channel; + ta.adc_integral = input_tp.adc_integral; + ta.adc_peak = input_tp.adc_peak; + ta.detid = input_tp.detid; + ta.type = TriggerActivity::Type::kTPC; + ta.algorithm = TriggerActivity::Algorithm::kPrescale; + + ta.inputs = tp_list; + + output_ta.push_back(ta); +} + +void +TAMakerPrescaleAlgorithm::configure(const nlohmann::json& config) +{ + TriggerActivityMaker::configure(config); +} + +// Register algo in TA Factory +REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerPrescaleAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerSupernovaAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerSupernovaAlgorithm.cpp new file mode 100644 index 0000000..e8aed9a --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAMakerSupernovaAlgorithm.cpp @@ -0,0 +1,87 @@ +/** + * @file TAMakerSupernovaAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TAMakerSupernovaAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TAMakerSupernovaAlgorithm" + +#include +#include + +using pd_clock = std::chrono::duration>; +using namespace triggeralgs; + +void +TAMakerSupernovaAlgorithm::process(const TriggerPrimitive& input_tp, std::vector& output_ta) +{ + // Time measurement + // auto now = std::chrono::steady_clock::now(); + // m_algorithm = (uint32_t)pd_clock(now.time_since_epoch()).count(); + + timestamp_t tend = input_tp.time_start + input_tp.samples_over_threshold * 32; // FIXME: Replace the hard-coded SOT to TOT scaling. + + if (m_time_start == 0) { + m_tp_list.erase(m_tp_list.begin(), m_tp_list.end()); + m_tp_list.push_back(input_tp); + m_time_start = input_tp.time_start; + m_time_end = tend; + m_time_peak = input_tp.samples_to_peak * 32 + input_tp.time_start; // FIXME: Replace STP to `time_peak` conversion. + m_channel_start = input_tp.channel; + m_channel_end = input_tp.channel; + m_channel_peak = input_tp.channel; + m_adc_integral = input_tp.adc_integral; + m_adc_peak = input_tp.adc_peak; + m_detid = input_tp.detid; + return; + } + + bool time_ok = is_time_consistent(input_tp); + bool channel_ok = is_channel_consistent(input_tp); + + if (!time_ok && !channel_ok) { + output_ta.push_back(MakeTriggerActivity()); + m_tp_list.erase(m_tp_list.begin(), m_tp_list.end()); + m_tp_list.push_back(input_tp); + m_time_start = input_tp.time_start; + m_time_end = tend; + m_time_peak = input_tp.samples_to_peak * 32 + input_tp.time_start; // FIXME: Replace STP to `time_peak` conversion. + m_channel_start = input_tp.channel; + m_channel_end = input_tp.channel; + m_channel_peak = input_tp.channel; + m_adc_integral = input_tp.adc_integral; + m_adc_peak = input_tp.adc_peak; + m_detid = input_tp.detid; + return; + } + + if (input_tp.time_start < m_time_start) + m_time_start = input_tp.time_start; + + if (tend > m_time_end) + m_time_end = tend; + + if (input_tp.adc_peak > m_adc_peak) { + m_time_peak = input_tp.samples_to_peak * 32 + input_tp.time_start; // FIXME: Replace STP to `time_peak` conversion. + m_adc_peak = input_tp.adc_peak; + m_channel_peak = input_tp.channel; + } + + if (input_tp.channel > m_channel_end) + m_channel_end = input_tp.channel; + + if (input_tp.channel < m_channel_start) + m_channel_start = input_tp.channel; + + m_tp_list.push_back(input_tp); + m_adc_integral += input_tp.adc_integral; + m_detid |= input_tp.detid; +} + +// Register algo in TA Factory +REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerSupernovaAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TAWindow.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAWindow.cpp new file mode 100644 index 0000000..2da86e3 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TAWindow.cpp @@ -0,0 +1,117 @@ +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TAWindow.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +namespace triggeralgs { + +//--- +void +TAWindow::add(const TriggerActivity& input_ta) +{ + + adc_integral += input_ta.adc_integral; + for (TriggerPrimitive tp : input_ta.inputs) { + channel_states[tp.channel]++; + } + // Perform binary search based on time_start. + uint16_t insert_at = 0; + for (auto ta : inputs) { + if (input_ta.time_start < ta.time_start) + break; + insert_at++; + } + inputs.insert(inputs.begin() + insert_at, input_ta); +} + +//--- +void +TAWindow::clear() +{ + inputs.clear(); + channel_states.clear(); + time_start = 0; + adc_integral = 0; +}; + +//--- +void +TAWindow::move(TriggerActivity const& input_ta, timestamp_t const& window_length) +{ + uint32_t n_tas_to_erase = 0; + for (auto ta : inputs) { + if (!(input_ta.time_start - ta.time_start < window_length)) { + n_tas_to_erase++; + adc_integral -= ta.adc_integral; + for (TriggerPrimitive tp : ta.inputs) { + channel_states[tp.channel]--; + // If a TA being removed from the window results in a channel no longer having + // any hits, remove from the states map so map.size() can be used for number + // channel hits. + if (channel_states[tp.channel] == 0) + channel_states.erase(tp.channel); + } + } else + break; + } + // Erase the TAs from the window. + inputs.erase(inputs.begin(), inputs.begin() + n_tas_to_erase); + // Make the window start time the start time of what is now the + // first TA. + if (inputs.size() != 0) { + time_start = inputs.front().time_start; + add(input_ta); + } else { + reset(input_ta); + } + // add(input_ta); + // time_start = inputs.front().time_start; +} + +//--- +void +TAWindow::reset(TriggerActivity const& input_ta) +{ + // Empty the channel and TA lists. + channel_states.clear(); + inputs.clear(); + // Set the start time of the window to be the start time of the + // input_ta. + time_start = input_ta.time_start; + // Start the total ADC integral. + adc_integral = input_ta.adc_integral; + // Start hit count for the hit channels. + for (TriggerPrimitive tp : input_ta.inputs) { + channel_states[tp.channel]++; + } + // Add the input TA to the TA list. + inputs.push_back(input_ta); +} + +std::ostream& +operator<<(std::ostream& os, const TAWindow& window) +{ + if (window.is_empty()) + os << "Window is empty!\n"; + else { + os << "Window start: " << window.time_start << ", end: " << window.inputs.back().time_start; + os << ". Total of: " << window.adc_integral << " ADC counts with " << window.inputs.size() << " TPs.\n"; + os << window.channel_states.size() << " independent channels have hits.\n"; + } + return os; +}; + +//--- +//--- +//--- +//--- +//--- +//--- + +} // namespace triggeralgs \ No newline at end of file diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerADCSimpleWindowAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerADCSimpleWindowAlgorithm.cpp new file mode 100644 index 0000000..872394f --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerADCSimpleWindowAlgorithm.cpp @@ -0,0 +1,45 @@ +/** + * @file TCMakerADCSimpleWindowAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ADCSimpleWindow/TCMakerADCSimpleWindowAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TCMakerADCSimpleWindowAlgorithm" + +#include + +using namespace triggeralgs; + +void +TCMakerADCSimpleWindowAlgorithm::process(const TriggerActivity& activity, std::vector& cand) +{ + // For now, if there is any single activity from any one detector element, emit + // a trigger candidate. + std::vector ta_list = {static_cast(activity)}; + + TriggerCandidate tc; + tc.time_start = activity.time_start; + tc.time_end = activity.time_end; + tc.time_candidate = activity.time_activity; + tc.detid = activity.detid; + tc.type = m_tc_type_out; + tc.algorithm = TriggerCandidate::Algorithm::kADCSimpleWindow; + + tc.inputs = ta_list; + + cand.push_back(tc); + +} + +void +TCMakerADCSimpleWindowAlgorithm::configure(const nlohmann::json &config) +{ + TriggerCandidateMaker::configure(config); +} + +REGISTER_TRIGGER_CANDIDATE_MAKER(TRACE_NAME, TCMakerADCSimpleWindowAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerBundleNAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerBundleNAlgorithm.cpp new file mode 100644 index 0000000..81cb5d7 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerBundleNAlgorithm.cpp @@ -0,0 +1,73 @@ +/** + * @file TCMakerBundleNAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/BundleN/TCMakerBundleNAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TCMakerBundleNAlgorithm" + +namespace triggeralgs { + +using Logging::TLVL_IMPORTANT; +using Logging::TLVL_DEBUG_HIGH; + +void TCMakerBundleNAlgorithm::set_tc_attributes() { + // Using the first TA as reference. + dunedaq::trgdataformats2::TriggerActivityData front_ta = m_current_tc.inputs.front(); + + m_current_tc.time_start = front_ta.time_start; + m_current_tc.time_end = m_current_tc.inputs.back().time_end; + m_current_tc.time_candidate = front_ta.time_start; // TODO: Conforming. Do we change this? + m_current_tc.detid = front_ta.detid; + m_current_tc.type = m_tc_type_out; + m_current_tc.algorithm = TriggerCandidate::Algorithm::kBundle; + return; +} + +bool TCMakerBundleNAlgorithm::bundle_condition() { + return m_current_tc.inputs.size() == m_bundle_size; +} + +void +TCMakerBundleNAlgorithm::process(const TriggerActivity& input_ta, std::vector& output_tcs) +{ + // Expect that TAs are inherently time ordered. + m_current_tc.inputs.push_back(input_ta); + + if (bundle_condition()) { + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TC:BN] Emitting BundleN TriggerCandidate with " << m_current_tc.inputs.size() << " TAs."; + set_tc_attributes(); + output_tcs.push_back(m_current_tc); + + // Reset the current. + m_current_tc = TriggerCandidate(); + } + + // Should never reach this step. In this case, send it out. + if (m_current_tc.inputs.size() > m_bundle_size) { + TLOG_DEBUG(TLVL_IMPORTANT) << "[TC:BN] Emitting large BundleN TriggerCandidate with " << m_current_tc.inputs.size() << " TAs."; + set_tc_attributes(); + output_tcs.push_back(m_current_tc); + + // Reset the current. + m_current_tc = TriggerCandidate(); + } +} + +void +TCMakerBundleNAlgorithm::configure(const nlohmann::json& config) +{ + TriggerCandidateMaker::configure(config); + if (config.is_object() && config.contains("bundle_size")) { + m_bundle_size = config["bundle_size"]; + } +} + +REGISTER_TRIGGER_CANDIDATE_MAKER(TRACE_NAME, TCMakerBundleNAlgorithm) +} // namespace triggeralgs + diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerChannelAdjacencyAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerChannelAdjacencyAlgorithm.cpp new file mode 100644 index 0000000..bcb3ed9 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerChannelAdjacencyAlgorithm.cpp @@ -0,0 +1,143 @@ +/** + * @file TCMakerChannelAdjacencyAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelAdjacency/TCMakerChannelAdjacencyAlgorithm.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Logging.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TCMakerChannelAdjacencyAlgorithm" + +#include +#include + +using namespace triggeralgs; + +using Logging::TLVL_DEBUG_ALL; +using Logging::TLVL_DEBUG_HIGH; +using Logging::TLVL_DEBUG_MEDIUM; +using Logging::TLVL_VERY_IMPORTANT; + +void +TCMakerChannelAdjacencyAlgorithm::process(const TriggerActivity& activity, + std::vector& output_tc) +{ + + // The first time process() is called, reset window object. + if (m_current_window.is_empty()) { + m_current_window.reset(activity); + m_activity_count++; + } + + // If the difference between the current TA's start time and the start of the window + // is less than the specified window size, add the TA to the window. + else if ((activity.time_start - m_current_window.time_start) < m_window_length) { + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TCM:CA] Window not yet complete, adding the activity to the window."; + m_current_window.add(activity); + } + // If it is not, move the window along. + else { + TLOG_DEBUG(TLVL_DEBUG_ALL) + << "[TCM:CA] TAWindow is at required length but specified threshold not met, shifting window along."; + m_current_window.move(activity, m_window_length); + } + + // If the addition of the current TA to the window would make it longer + // than the specified window length, don't add it but check whether the sum of all adc in + // the existing window is above the specified threshold. If it is, and we are triggering on ADC, + // make a TA and start a fresh window with the current TP. + if (m_current_window.adc_integral > m_adc_threshold && m_trigger_on_adc) { + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TCM:CA] m_current_window.adc_integral " << m_current_window.adc_integral + << " - m_adc_threshold " << m_adc_threshold; + TriggerCandidate tc = construct_tc(); + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TCM:CA] tc.time_start=" << tc.time_start << " tc.time_end=" << tc.time_end + << " len(tc.inputs) " << tc.inputs.size(); + + for (const auto& ta : tc.inputs) { + TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TCM:CA] [TA] ta.time_start=" << ta.time_start << " ta.time_end=" << ta.time_end + << " ta.adc_integral=" << ta.adc_integral; + } + + output_tc.push_back(tc); + m_current_window.clear(); + } + + // If the addition of the current TA to the window would make it longer + // than the specified window length, don't add it but check whether the number of hit channels in + // the existing window is above the specified threshold. If it is, and we are triggering on channels, + // make a TC and start a fresh window with the current TA. + else if (m_current_window.n_channels_hit() > m_n_channels_threshold && m_trigger_on_n_channels) { + output_tc.push_back(construct_tc()); + m_current_window.clear(); + } + + m_activity_count++; + return; +} + +void +TCMakerChannelAdjacencyAlgorithm::configure(const nlohmann::json& config) +{ + TriggerCandidateMaker::configure(config); + + if (config.is_object()) { + if (config.contains("trigger_on_adc")) + m_trigger_on_adc = config["trigger_on_adc"]; + if (config.contains("trigger_on_n_channels")) + m_trigger_on_n_channels = config["trigger_on_n_channels"]; + if (config.contains("adc_threshold")) + m_adc_threshold = config["adc_threshold"]; + if (config.contains("n_channels_threshold")) + m_n_channels_threshold = config["n_channels_threshold"]; + if (config.contains("window_length")) + m_window_length = config["window_length"]; + } + + // Both trigger flags were false. This will never trigger. + if (!m_trigger_on_adc && !m_trigger_on_n_channels) { + TLOG_DEBUG(TLVL_VERY_IMPORTANT) << "[TCM:CA] Not triggering! All trigger flags are false!"; +// throw BadConfiguration(ERS_HERE, TRACE_NAME); + } + + return; +} + +TriggerCandidate +TCMakerChannelAdjacencyAlgorithm::construct_tc() const +{ + TriggerActivity latest_ta_in_window = m_current_window.inputs.back(); + + TriggerCandidate tc; + tc.time_start = m_current_window.time_start; + tc.time_end = latest_ta_in_window.inputs.back().time_start; + tc.time_candidate = m_current_window.time_start; + tc.detid = latest_ta_in_window.detid; + tc.type = m_tc_type_out; + tc.algorithm = TriggerCandidate::Algorithm::kChannelAdjacency; + + // Take the list of triggeralgs::TriggerActivity in the current + // window and convert them (implicitly) to detdataformats' + // TriggerActivityData, which is the base class of TriggerActivity + for (auto& ta : m_current_window.inputs) { + tc.inputs.push_back(ta); + if (ta.time_end > tc.time_end) { + tc.time_end = ta.time_end; + } + } + + return tc; +} + +// Functions below this line are for debugging purposes. +void +TCMakerChannelAdjacencyAlgorithm::add_window_to_record(TAWindow window) +{ + m_window_record.push_back(window); + return; +} + +REGISTER_TRIGGER_CANDIDATE_MAKER(TRACE_NAME, TCMakerChannelAdjacencyAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerChannelDistanceAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerChannelDistanceAlgorithm.cpp new file mode 100644 index 0000000..9d25b63 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerChannelDistanceAlgorithm.cpp @@ -0,0 +1,80 @@ +/** + * @file TCMakerChannelDistanceAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/ChannelDistance/TCMakerChannelDistanceAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TCMakerChannelDistanceAlgorithm" + +namespace triggeralgs { + +void +TCMakerChannelDistanceAlgorithm::set_new_tc(const TriggerActivity& input_ta) +{ + m_current_tc = TriggerCandidate(); + m_current_tc.inputs.push_back(input_ta); + m_current_tp_count = input_ta.inputs.size(); + return; +} + +void +TCMakerChannelDistanceAlgorithm::configure(const nlohmann::json& config) +{ + TriggerCandidateMaker::configure(config); + + if (config.contains("max_tp_count")) + m_max_tp_count = config["max_tp_count"]; + return; +} + +void +TCMakerChannelDistanceAlgorithm::set_tc_attributes() +{ + auto& first_ta = m_current_tc.inputs.front(); + auto& last_ta = m_current_tc.inputs.back(); + + m_current_tc.time_start = first_ta.time_start; + m_current_tc.time_end = last_ta.time_end; + m_current_tc.time_candidate = last_ta.time_start; // Since this is the TA that closed the TC. + + m_current_tc.detid = first_ta.detid; + m_current_tc.algorithm = TriggerCandidate::Algorithm::kChannelDistance; + m_current_tc.type = m_tc_type_out; + return; +} + +void +TCMakerChannelDistanceAlgorithm::process(const TriggerActivity& input_ta, + std::vector& output_tcs) +{ + + // Start a new TC if not already going. + if (m_current_tc.inputs.empty()) { + set_new_tc(input_ta); + return; + } + + // Check to close the TC based on TP contents. + if (input_ta.inputs.size() + m_current_tp_count > m_max_tp_count) { + set_tc_attributes(); + output_tcs.push_back(m_current_tc); + + set_new_tc(input_ta); + return; + } + + // Append the new TA and increase the TP count. + m_current_tc.inputs.push_back(input_ta); + m_current_tp_count += input_ta.inputs.size(); + return; +} + +// Register algo in TC Factory +REGISTER_TRIGGER_CANDIDATE_MAKER(TRACE_NAME, TCMakerChannelDistanceAlgorithm) + +} // namespace triggeralgs diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerDBSCANAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerDBSCANAlgorithm.cpp new file mode 100644 index 0000000..5165e54 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerDBSCANAlgorithm.cpp @@ -0,0 +1,77 @@ +/** + * @file TCMakerDBSCANAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/TCMakerDBSCANAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TCMakerDBSCANAlgorithm" + +namespace triggeralgs { + +void +TCMakerDBSCANAlgorithm::set_new_tc(const TriggerActivity& input_ta) +{ + m_current_tc = TriggerCandidate(); + m_current_tc.inputs.push_back(input_ta); + m_current_tp_count = input_ta.inputs.size(); + return; +} + +void +TCMakerDBSCANAlgorithm::configure(const nlohmann::json& config) +{ + TriggerCandidateMaker::configure(config); + + if (config.contains("max_tp_count")) + m_max_tp_count = config["max_tp_count"]; + return; +} + +void +TCMakerDBSCANAlgorithm::set_tc_attributes() +{ + auto& first_ta = m_current_tc.inputs.front(); + auto& last_ta = m_current_tc.inputs.back(); + + m_current_tc.time_start = first_ta.time_start; + m_current_tc.time_end = last_ta.time_end; + m_current_tc.time_candidate = last_ta.time_start; // Since this is the TA that closed the TC. + + m_current_tc.detid = first_ta.detid; + m_current_tc.algorithm = TriggerCandidate::Algorithm::kDBSCAN; + m_current_tc.type = m_tc_type_out; + return; +} + +void +TCMakerDBSCANAlgorithm::process(const TriggerActivity& input_ta, std::vector& output_tcs) +{ + // Start a new TC if not already going. + if (m_current_tc.inputs.empty()) { + set_new_tc(input_ta); + return; + } + + // Check to close the TC based on TP contents. + if (input_ta.inputs.size() + m_current_tp_count > m_max_tp_count) { + set_tc_attributes(); + output_tcs.push_back(m_current_tc); + set_new_tc(input_ta); + return; + } + + // Append the new TA and increase the TP count. + m_current_tc.inputs.push_back(input_ta); + m_current_tp_count += input_ta.inputs.size(); + return; +} + +// Register algo in TC Factory. +REGISTER_TRIGGER_CANDIDATE_MAKER(TRACE_NAME, TCMakerDBSCANAlgorithm) + +} // namespace triggeralgs diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerHorizontalMuonAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerHorizontalMuonAlgorithm.cpp new file mode 100644 index 0000000..0174808 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerHorizontalMuonAlgorithm.cpp @@ -0,0 +1,218 @@ +/** + * @file TCMakerHorizontalMuonAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/HorizontalMuon/TCMakerHorizontalMuonAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TCMakerHorizontalMuonAlgorithm" + +#include +#include + +using namespace triggeralgs; + +using Logging::TLVL_DEBUG_ALL; +using Logging::TLVL_DEBUG_HIGH; +using Logging::TLVL_DEBUG_MEDIUM; + +void +TCMakerHorizontalMuonAlgorithm::process(const TriggerActivity& activity, + std::vector& output_tc) +{ + + std::vector ta_list = { static_cast( + activity) }; + + // The first time operator is called, reset window object. + if (m_current_window.is_empty()) { + m_current_window.reset(activity); + m_activity_count++; + + // TriggerCandidate tc = construct_tc(); + // output_tc.push_back(tc); + + // m_current_window.clear(); + // return; + } + + // If the difference between the current TA's start time and the start of the window + // is less than the specified window size, add the TA to the window. + else if ((activity.time_start - m_current_window.time_start) < m_window_length) { + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TCM:HM] Window not yet complete, adding the activity to the window."; + m_current_window.add(activity); + } + // If it is not, move the window along. + else { + TLOG_DEBUG(TLVL_DEBUG_ALL) + << "[TCM:HM] TAWindow is at required length but specified threshold not met, shifting window along."; + m_current_window.move(activity, m_window_length); + } + + // If the addition of the current TA to the window would make it longer + // than the specified window length, don't add it but check whether the sum of all adc in + // the existing window is above the specified threshold. If it is, and we are triggering on ADC, + // make a TA and start a fresh window with the current TP. + if (m_current_window.adc_integral > m_adc_threshold && m_trigger_on_adc) { + // TLOG_DEBUG(TRACE_NAME) << "ADC integral in window is greater than specified threshold."; + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TCM:HM] m_current_window.adc_integral " << m_current_window.adc_integral + << " - m_adc_threshold " << m_adc_threshold; + tc_number++; + TriggerCandidate tc = construct_tc(); + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TCM:HM] tc.time_start=" << tc.time_start << " tc.time_end=" << tc.time_end + << " len(tc.inputs) " << tc.inputs.size(); + + for (const auto& ta : tc.inputs) { + TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TCM:HM] [TA] ta.time_start=" << ta.time_start << " ta.time_end=" << ta.time_end + << " ta.adc_integral=" << ta.adc_integral; + } + + output_tc.push_back(tc); + // m_current_window.reset(activity); + m_current_window.clear(); + } + + // If the addition of the current TA to the window would make it longer + // than the specified window length, don't add it but check whether the number of hit channels in + // the existing window is above the specified threshold. If it is, and we are triggering on channels, + // make a TC and start a fresh window with the current TA. + else if (m_current_window.n_channels_hit() > m_n_channels_threshold && m_trigger_on_n_channels) { + tc_number++; + output_tc.push_back(construct_tc()); + + // m_current_window.reset(activity); + m_current_window.clear(); + } + + // // If it is not, move the window along. + // else { + // // TLOG_DEBUG(TRACE_NAME) << "TAWindow is at required length but specified threshold not met." + // // << "shifting window along."; + // m_current_window.move(activity, m_window_length); + // } + + m_activity_count++; + return; +} + +void +TCMakerHorizontalMuonAlgorithm::configure(const nlohmann::json& config) +{ + TriggerCandidateMaker::configure(config); + + if (config.is_object()) { + if (config.contains("trigger_on_adc")) + m_trigger_on_adc = config["trigger_on_adc"]; + if (config.contains("trigger_on_n_channels")) + m_trigger_on_n_channels = config["trigger_on_n_channels"]; + if (config.contains("adc_threshold")) + m_adc_threshold = config["adc_threshold"]; + if (config.contains("n_channels_threshold")) + m_n_channels_threshold = config["n_channels_threshold"]; + if (config.contains("window_length")) + m_window_length = config["window_length"]; + } + if (m_trigger_on_adc && m_trigger_on_n_channels) { + TLOG_DEBUG(TLVL_VERY_IMPORTANT) << "[TCM:HM] Triggering on ADC count and number of channels is not supported."; +// throw BadConfiguration(ERS_HERE, TRACE_NAME); + } + if (!m_trigger_on_adc && !m_trigger_on_n_channels) { + TLOG_DEBUG(TLVL_VERY_IMPORTANT) << "[TCM:HM] Not triggering! All trigger flags are false!"; +// throw BadConfiguration(ERS_HERE, TRACE_NAME); + } + + return; +} + +TriggerCandidate +TCMakerHorizontalMuonAlgorithm::construct_tc() const +{ + TriggerActivity latest_ta_in_window = m_current_window.inputs.back(); + + TriggerCandidate tc; + tc.time_start = m_current_window.time_start; + tc.time_end = latest_ta_in_window.inputs.back().time_start; + tc.time_candidate = m_current_window.time_start; + tc.detid = latest_ta_in_window.detid; + tc.type = m_tc_type_out; + tc.algorithm = TriggerCandidate::Algorithm::kHorizontalMuon; + + // Take the list of triggeralgs::TriggerActivity in the current + // window and convert them (implicitly) to detdataformats' + // TriggerActivityData, which is the base class of TriggerActivity + for (auto& ta : m_current_window.inputs) { + tc.inputs.push_back(ta); + if (ta.time_end > tc.time_end) { + tc.time_end = ta.time_end; + } + } + + return tc; +} + +bool +TCMakerHorizontalMuonAlgorithm::check_adjacency() const +{ + // FIX ME: An adjacency check on the channels which have hits. + return true; +} + +// Functions below this line are for debugging purposes. +void +TCMakerHorizontalMuonAlgorithm::add_window_to_record(TAWindow window) +{ + m_window_record.push_back(window); + return; +} + +void +TCMakerHorizontalMuonAlgorithm::dump_window_record() +{ + // FIX ME: Need to index this outfile in the name by detid or something similar. + std::ofstream outfile; + outfile.open("window_record_tcm.csv", std::ios_base::app); + + for (auto window : m_window_record) { + outfile << window.time_start << ","; + outfile << window.inputs.back().time_start << ","; + outfile << window.inputs.back().time_start - window.time_start << ","; + outfile << window.adc_integral << ","; + outfile << window.n_channels_hit() << ","; + outfile << window.inputs.size() << std::endl; + } + + outfile.close(); + + m_window_record.clear(); + + return; +} + +/* +void +TCMakerHorizontalMuonAlgorithm::flush(timestamp_t, std::vector& output_tc) +{ + // Check the status of the current window, construct TC if conditions are met. Regardless + // of whether the conditions are met, reset the window. + if(m_current_window.adc_integral > m_adc_threshold && m_trigger_on_adc){ + //else if(m_current_window.adc_integral > m_conf.adc_threshold && m_conf.trigger_on_adc){ + //TLOG_DEBUG(TRACE_NAME) << "ADC integral in window is greater than specified threshold."; + output_tc.push_back(construct_tc()); + } + else if(m_current_window.n_channels_hit() > m_n_channels_threshold && m_trigger_on_n_channels){ + //else if(m_current_window.n_channels_hit() > m_conf.n_channels_threshold && m_conf.trigger_on_n_channels){ + //TLOG_DEBUG(TRACE_NAME) << "Number of channels hit in the window is greater than specified threshold."; + output_tc.push_back(construct_tc()); + } + + //TLOG_DEBUG(TRACE_NAME) << "Clearing the current window, on the arrival of the next input_tp, the window will be +reset."; m_current_window.clear(); + + return; +}*/ + +REGISTER_TRIGGER_CANDIDATE_MAKER(TRACE_NAME, TCMakerHorizontalMuonAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerMichelElectronAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerMichelElectronAlgorithm.cpp new file mode 100644 index 0000000..0731fb1 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerMichelElectronAlgorithm.cpp @@ -0,0 +1,214 @@ +/** + * @file TCMakerMichelElectronAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/MichelElectron/TCMakerMichelElectronAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TCMakerMichelElectronAlgorithm" + +#include + +using namespace triggeralgs; + +using Logging::TLVL_DEBUG_ALL; +using Logging::TLVL_DEBUG_HIGH; +using Logging::TLVL_DEBUG_LOW; +using Logging::TLVL_DEBUG_INFO; +using Logging::TLVL_VERY_IMPORTANT; + +void +TCMakerMichelElectronAlgorithm::process(const TriggerActivity& activity, + std::vector& output_tc) +{ + + std::vector ta_list = { static_cast( + activity) }; + + // The first time process() is called, reset window object. + if (m_current_window.is_empty()) { + m_current_window.reset(activity); + m_activity_count++; + // Trivial TC Logic: + // If the request has been made to not trigger on number of channels or + // total adc, simply construct a trigger candidate from any single activity. + if ((!m_trigger_on_adc) && (!m_trigger_on_n_channels)) { + + // add_window_to_record(m_current_window); + // dump_window_record(); + TLOG_DEBUG(TLVL_DEBUG_LOW) << "[TCM:ME] Constructing TC."; + + TriggerCandidate tc = construct_tc(); + output_tc.push_back(tc); + + // Clear the current window (only has a single TA in it) + m_current_window.clear(); + } + return; + } + + // FIX ME: Only want to call this if running in debug mode. + // add_window_to_record(m_current_window); + + // If the difference between the current TA's start time and the start of the window + // is less than the specified window size, add the TA to the window. + if ((activity.time_start - m_current_window.time_start) < m_window_length) { + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TCM:ME] Window not yet complete, adding the activity to the window."; + m_current_window.add(activity); + } + // If the addition of the current TA to the window would make it longer + // than the specified window length, don't add it but check whether the sum of all adc in + // the existing window is above the specified threshold. If it is, and we are triggering on ADC, + // make a TA and start a fresh window with the current TP. + else if (m_current_window.adc_integral > m_adc_threshold && m_trigger_on_adc) { + TLOG_DEBUG(TLVL_DEBUG_LOW) << "[TCM:ME] ADC integral in window is greater than specified threshold."; + TriggerCandidate tc = construct_tc(); + + output_tc.push_back(tc); + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TCM:ME] Resetting window with activity."; + m_current_window.reset(activity); + } + // If the addition of the current TA to the window would make it longer + // than the specified window length, don't add it but check whether the number of hit channels in + // the existing window is above the specified threshold. If it is, and we are triggering on channels, + // make a TC and start a fresh window with the current TA. + else if (m_current_window.n_channels_hit() > m_n_channels_threshold && m_trigger_on_n_channels) { + tc_number++; + // output_tc.push_back(construct_tc()); + m_current_window.reset(activity); + TLOG_DEBUG(TLVL_DEBUG_INFO) << "[TCM:ME] Should not see this!"; + } + // If it is not, move the window along. + else { + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TCM:ME] Window is at required length but specified threshold not met, shifting window along."; + m_current_window.move(activity, m_window_length); + } + + //TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TCM:ME] " m_current_window; + + m_activity_count++; + + // if(m_activity_count % 500 == 0) dump_window_record(); + + return; +} + +void +TCMakerMichelElectronAlgorithm::configure(const nlohmann::json& config) +{ + TriggerCandidateMaker::configure(config); + + // FIX ME: Use some schema here. Also can't work out how to pass booleans. + if (config.is_object()) { + if (config.contains("trigger_on_adc")) + m_trigger_on_adc = config["trigger_on_adc"]; + if (config.contains("trigger_on_n_channels")) + m_trigger_on_n_channels = config["trigger_on_n_channels"]; + if (config.contains("adc_threshold")) + m_adc_threshold = config["adc_threshold"]; + if (config.contains("n_channels_threshold")) + m_n_channels_threshold = config["n_channels_threshold"]; + if (config.contains("window_length")) + m_window_length = config["window_length"]; + // if (config.contains("channel_map")) m_channel_map = config["channel_map"]; + } + if (m_trigger_on_adc && m_trigger_on_n_channels) { + TLOG_DEBUG(TLVL_VERY_IMPORTANT) << "[TCM:ME] Triggering on ADC count and number of channels is not supported."; +// throw BadConfiguration(ERS_HERE, TRACE_NAME); + } + if (!m_trigger_on_adc && !m_trigger_on_n_channels) { + TLOG_DEBUG(TLVL_DEBUG_LOW) << "[TCM:ME] Both trigger flags are false. Passing TAs through 1:1."; + } + + return; +} + +TriggerCandidate +TCMakerMichelElectronAlgorithm::construct_tc() const +{ + TriggerActivity latest_ta_in_window = m_current_window.inputs.back(); + + TriggerCandidate tc; + tc.time_start = m_current_window.time_start; + tc.time_end = latest_ta_in_window.time_end; + tc.time_candidate = m_current_window.time_start; + tc.detid = latest_ta_in_window.detid; + tc.type = m_tc_type_out; + tc.algorithm = TriggerCandidate::Algorithm::kMichelElectron; + + // Take the list of triggeralgs::TriggerActivity in the current + // window and convert them (implicitly) to detdataformats' + // TriggerActivityData, which is the base class of TriggerActivity + for (auto& ta : m_current_window.inputs) { + tc.inputs.push_back(ta); + } + + return tc; +} + +bool +TCMakerMichelElectronAlgorithm::check_adjacency() const +{ + // FIX ME: An adjacency check on the channels which have hits. + return true; +} + +// Functions below this line are for debugging purposes. +void +TCMakerMichelElectronAlgorithm::add_window_to_record(Window window) +{ + m_window_record.push_back(window); + return; +} + +void +TCMakerMichelElectronAlgorithm::dump_window_record() +{ + // FIX ME: Need to index this outfile in the name by detid or something similar. + std::ofstream outfile; + outfile.open("window_record_tcm.csv", std::ios_base::app); + + for (auto window : m_window_record) { + outfile << window.time_start << ","; + outfile << window.inputs.back().time_start << ","; + outfile << window.inputs.back().time_start - window.time_start << ","; + outfile << window.adc_integral << ","; + outfile << window.n_channels_hit() << ","; + outfile << window.inputs.size() << std::endl; + } + + outfile.close(); + + m_window_record.clear(); + + return; +} + +/* +void +TCMakerMichelElectronAlgorithm::flush(timestamp_t, std::vector& output_tc) +{ + // Check the status of the current window, construct TC if conditions are met. Regardless + // of whether the conditions are met, reset the window. + if(m_current_window.adc_integral > m_adc_threshold && m_trigger_on_adc){ + //else if(m_current_window.adc_integral > m_conf.adc_threshold && m_conf.trigger_on_adc){ + //TLOG_DEBUG(TRACE_NAME) << "ADC integral in window is greater than specified threshold."; + output_tc.push_back(construct_tc()); + } + else if(m_current_window.n_channels_hit() > m_n_channels_threshold && m_trigger_on_n_channels){ + //else if(m_current_window.n_channels_hit() > m_conf.n_channels_threshold && m_conf.trigger_on_n_channels){ + //TLOG_DEBUG(TRACE_NAME) << "Number of channels hit in the window is greater than specified threshold."; + output_tc.push_back(construct_tc()); + } + + //TLOG_DEBUG(TRACE_NAME) << "Clearing the current window, on the arrival of the next input_tp, the window will be +reset."; m_current_window.clear(); + + return; +}*/ + +REGISTER_TRIGGER_CANDIDATE_MAKER(TRACE_NAME, TCMakerMichelElectronAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerPlaneCoincidenceAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerPlaneCoincidenceAlgorithm.cpp new file mode 100644 index 0000000..3bd4f03 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerPlaneCoincidenceAlgorithm.cpp @@ -0,0 +1,184 @@ +/** + * @file TCMakerPlaneCoincidenceAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2021. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/PlaneCoincidence/TCMakerPlaneCoincidenceAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TCMakerPlaneCoincidenceAlgorithm" + +#include + +using namespace triggeralgs; + +using Logging::TLVL_DEBUG_HIGH; +using Logging::TLVL_DEBUG_MEDIUM; +using Logging::TLVL_DEBUG_LOW; +using Logging::TLVL_DEBUG_INFO; +using Logging::TLVL_VERY_IMPORTANT; + +void +TCMakerPlaneCoincidenceAlgorithm::process(const TriggerActivity& activity, + std::vector& output_tc) +{ + + std::vector ta_list = { static_cast( + activity) }; + + // The first time process is called, reset window object. + if (m_current_window.is_empty()) { + m_current_window.reset(activity); + m_activity_count++; + // Trivial TC Logic: + // If the request has been made to not trigger on number of channels or + // total adc, simply construct a trigger candidate from any single activity. + if ((!m_trigger_on_adc) && (!m_trigger_on_n_channels)) { + + // add_window_to_record(m_current_window); + // dump_window_record(); + TLOG_DEBUG(TLVL_DEBUG_LOW) << "[TCM:PC] Constructing TC."; + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TCM:PC] Activity count: " << m_activity_count; + TriggerCandidate tc = construct_tc(); + output_tc.push_back(tc); + + // Clear the current window (only has a single TA in it) + m_current_window.clear(); + } + return; + } + + // FIX ME: Only want to call this if running in debug mode. + // add_window_to_record(m_current_window); + + // If the difference between the current TA's start time and the start of the window + // is less than the specified window size, add the TA to the window. + if ((activity.time_start - m_current_window.time_start) < m_window_length) { + m_current_window.add(activity); + } + // If the addition of the current TA to the window would make it longer + // than the specified window length, don't add it but check whether the sum of all adc in + // the existing window is above the specified threshold. If it is, and we are triggering on ADC, + // make a TA and start a fresh window with the current TP. + else if (m_current_window.adc_integral > m_adc_threshold && m_trigger_on_adc) { + TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TCM:PC] ADC integral in window is greater than specified threshold."; + TriggerCandidate tc = construct_tc(); + + output_tc.push_back(tc); + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TCM:PC] Resetting window with activity."; + m_current_window.reset(activity); + } + // If the addition of the current TA to the window would make it longer + // than the specified window length, don't add it but check whether the number of hit channels in + // the existing window is above the specified threshold. If it is, and we are triggering on channels, + // make a TC and start a fresh window with the current TA. + else if (m_current_window.n_channels_hit() > m_n_channels_threshold && m_trigger_on_n_channels) { + // TODO 04-2024: This case appears unsupported. Throwing error for now, but should this be removed? + tc_number++; + // output_tc.push_back(construct_tc()); + m_current_window.reset(activity); + TLOG_DEBUG(TLVL_DEBUG_INFO) << "[TCM:PC] Should not see this!"; + } + // If it is not, move the window along. + else { + TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TCM:PC] TAWindow is at required length but specified threshold not met, shifting window along."; + m_current_window.move(activity, m_window_length); + } + + m_activity_count++; + + return; +} + +void +TCMakerPlaneCoincidenceAlgorithm::configure(const nlohmann::json& config) +{ + TriggerCandidateMaker::configure(config); + if (config.is_object()) { + if (config.contains("trigger_on_adc")) + m_trigger_on_adc = config["trigger_on_adc"]; + if (config.contains("trigger_on_n_channels")) + m_trigger_on_n_channels = config["trigger_on_n_channels"]; + if (config.contains("adc_threshold")) + m_adc_threshold = config["adc_threshold"]; + if (config.contains("n_channels_threshold")) + m_n_channels_threshold = config["n_channels_threshold"]; + if (config.contains("window_length")) + m_window_length = config["window_length"]; + } + if (m_trigger_on_n_channels) { + TLOG_DEBUG(TLVL_VERY_IMPORTANT) << "[TCM:PC] Using trigger_on_n_channels is not supported."; +// throw BadConfiguration(ERS_HERE, TRACE_NAME); + } + if (!m_trigger_on_adc && !m_trigger_on_n_channels) { + TLOG_DEBUG(TLVL_DEBUG_LOW) << "[TCM:PC] Both trigger flags are false. Passing TAs through 1:1."; + } + + return; +} + +TriggerCandidate +TCMakerPlaneCoincidenceAlgorithm::construct_tc() const +{ + TriggerActivity latest_ta_in_window = m_current_window.inputs.back(); + + TriggerCandidate tc; + tc.time_start = m_current_window.time_start; + tc.time_end = latest_ta_in_window.time_end; + tc.time_candidate = m_current_window.time_start; + tc.detid = latest_ta_in_window.detid; + tc.type = m_tc_type_out; + tc.algorithm = TriggerCandidate::Algorithm::kPlaneCoincidence; + + // Take the list of triggeralgs::TriggerActivity in the current + // window and convert them (implicitly) to detdataformats' + // TriggerActivityData, which is the base class of TriggerActivity + for (auto& ta : m_current_window.inputs) { + tc.inputs.push_back(ta); + } + + return tc; +} + +bool +TCMakerPlaneCoincidenceAlgorithm::check_adjacency() const +{ + // FIX ME: An adjacency check on the channels which have hits. + return true; +} + +// Functions below this line are for debugging purposes. +void +TCMakerPlaneCoincidenceAlgorithm::add_window_to_record(TAWindow window) +{ + m_window_record.push_back(window); + return; +} + +void +TCMakerPlaneCoincidenceAlgorithm::dump_window_record() +{ + // FIX ME: Need to index this outfile in the name by detid or something similar. + std::ofstream outfile; + outfile.open("window_record_tcm.csv", std::ios_base::app); + + for (auto window : m_window_record) { + outfile << window.time_start << ","; + outfile << window.inputs.back().time_start << ","; + outfile << window.inputs.back().time_start - window.time_start << ","; + outfile << window.adc_integral << ","; + outfile << window.n_channels_hit() << ","; + outfile << window.inputs.size() << std::endl; + } + + outfile.close(); + + m_window_record.clear(); + + return; +} + +REGISTER_TRIGGER_CANDIDATE_MAKER(TRACE_NAME, TCMakerPlaneCoincidenceAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerPrescaleAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerPrescaleAlgorithm.cpp new file mode 100644 index 0000000..34544dc --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerPrescaleAlgorithm.cpp @@ -0,0 +1,50 @@ +/** + * @file TCMakerPrescaleAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Prescale/TCMakerPrescaleAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TCMakerPrescaleAlgorithm" + +#include + +using namespace triggeralgs; + +void +TCMakerPrescaleAlgorithm::process(const TriggerActivity& activity, std::vector& cand) +{ + std::vector ta_list; + ta_list.push_back(static_cast(activity)); + + TriggerCandidate tc; + tc.time_start = activity.time_start; + tc.time_end = activity.time_end; + tc.time_candidate = activity.time_start; + tc.detid = activity.detid; + tc.type = m_tc_type_out; + tc.algorithm = TriggerCandidate::Algorithm::kPrescale; + + tc.inputs = ta_list; + + using namespace std::chrono; + + // Update OpMon Variable(s) + uint64_t system_time = duration_cast(system_clock::now().time_since_epoch()).count(); + uint64_t data_time = activity.time_start*16e-6; // Convert 62.5 MHz ticks to ms + m_data_vs_system_time.store(data_time - system_time); // Store the difference for OpMon + + cand.push_back(tc); +} + +void +TCMakerPrescaleAlgorithm::configure(const nlohmann::json &config) +{ + TriggerCandidateMaker::configure(config); +} + +REGISTER_TRIGGER_CANDIDATE_MAKER(TRACE_NAME, TCMakerPrescaleAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerSupernovaAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerSupernovaAlgorithm.cpp new file mode 100644 index 0000000..c62a9c2 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TCMakerSupernovaAlgorithm.cpp @@ -0,0 +1,44 @@ +/** + * @file TCMakerSupernovaAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TCMakerSupernovaAlgorithm.hpp" + +#include "TRACE/trace.h" +#define TRACE_NAME "TCMakerSupernovaAlgorithm" + +using namespace triggeralgs; + +void +TCMakerSupernovaAlgorithm::process(const TriggerActivity& activity, std::vector& cand) +{ + timestamp_t time = activity.time_start; + FlushOldActivity(time); // get rid of old activities in the buffer + if (activity.inputs.size() > m_hit_threshold) + m_activity.push_back(static_cast(activity)); + + // Yay! we have a trigger! + if (m_activity.size() > m_threshold) { + + detid_t detid = dunedaq::trgdataformats2::WHOLE_DETECTOR; + + TriggerCandidate tc; + tc.time_start = time - 500'000'000; // time_start (10 seconds before the start of the activity) + tc.time_end = activity.time_end; // time_end; but that should probably be _at least_ this number + tc.time_candidate = time; + tc.detid = detid; + tc.type = m_tc_type_out; // type ( flag that says what type of trigger might be (e.g. SN/Muon/Beam) ) + tc.algorithm = TriggerCandidate::Algorithm::kSupernova; // algorithm ( flag that says which algorithm created the trigger (e.g. SN/HE/Solar) ) + tc.inputs = m_activity; + + m_activity.clear(); + // Give the trigger word back + cand.push_back(tc); + } +} + +REGISTER_TRIGGER_CANDIDATE_MAKER(TRACE_NAME, TCMakerSupernovaAlgorithm) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TDMakerSupernovaAlgorithm.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TDMakerSupernovaAlgorithm.cpp new file mode 100644 index 0000000..c764e80 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TDMakerSupernovaAlgorithm.cpp @@ -0,0 +1,45 @@ +/** + * @file TDMakerSupernovaAlgorithm.cpp + * + * This is part of the DUNE DAQ Application Framework, copyright 2020. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/Supernova/TDMakerSupernovaAlgorithm.hpp" + +#include +#include +#include +#include + +using pd_clock = std::chrono::duration>; +using namespace triggeralgs; + +void +TDMakerSupernovaAlgorithm::operator()(const TriggerCandidate& cand, std::vector& decisions) +{ + + std::vector vCand; + vCand.push_back(cand); + + auto now = std::chrono::steady_clock::now(); + // Timestamp + uint32_t algorithm = (uint32_t)pd_clock(now.time_since_epoch()).count(); // NOLINT(build/unsigned) + + TriggerDecision trigger{ cand.time_start, + cand.time_end, + cand.time_candidate, + 0, + 0, + 0, + // cand.detid, + 0, + algorithm, + cand.version, + vCand }; + + // Give the trigger word back + decisions.push_back(trigger); + return; +} diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/TPWindow.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/TPWindow.cpp new file mode 100644 index 0000000..c96a94d --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/TPWindow.cpp @@ -0,0 +1,109 @@ + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TPWindow.hpp" + +#include +#include +#include +#include +#include +#include + +namespace triggeralgs { + +bool +TPWindow::is_empty() const +{ + return inputs.empty(); +} + +void +TPWindow::add(TriggerPrimitive const& input_tp) +{ + // Add the input TP's contribution to the total ADC, increase hit + // channel's hit count and add it to the TP list. + adc_integral += input_tp.adc_integral; + channel_states[input_tp.channel]++; + inputs.push_back(input_tp); +} + +void +TPWindow::clear() +{ + inputs.clear(); + channel_states.clear(); + time_start = 0; + adc_integral = 0; +} + +uint16_t +TPWindow::n_channels_hit() +{ + return channel_states.size(); +} + +void +TPWindow::move(TriggerPrimitive const& input_tp, timestamp_t const& window_length) +{ + // Find all of the TPs in the window that need to be removed + // if the input_tp is to be added and the size of the window + // is to be conserved. + // Substract those TPs' contribution from the total window ADC and remove their + // contributions to the hit counts. + uint32_t n_tps_to_erase = 0; + for (auto tp : inputs) { + if (!(input_tp.time_start - tp.time_start < window_length)) { + n_tps_to_erase++; + adc_integral -= tp.adc_integral; + channel_states[tp.channel]--; + // If a TP being removed from the window results in a channel no longer having + // any hits, remove from the states map so map.size() can be used for number + // channels hit. + if (channel_states[tp.channel] == 0) + channel_states.erase(tp.channel); + } else + break; + } + // Erase the TPs from the window. + inputs.erase(inputs.begin(), inputs.begin() + n_tps_to_erase); + // Make the window start time the start time of what is now the first TP. + + if (inputs.size() != 0) { + time_start = inputs.front().time_start; + add(input_tp); + } else { + reset(input_tp); + } +} + +void +TPWindow::reset(TriggerPrimitive const& input_tp) +{ + + // Empty the channel and TP lists. + channel_states.clear(); + inputs.clear(); + // Set the start time of the window to be the start time of theinput_tp. + time_start = input_tp.time_start; + // Start the total ADC integral. + adc_integral = input_tp.adc_integral; + // Start hit count for the hit channel. + channel_states[input_tp.channel]++; + // Add the input TP to the TP list. + inputs.push_back(input_tp); + // std::cout << "Number of channels hit: " << n_channels_hit() << std::endl; +} + +std::ostream& +operator<<(std::ostream& os, const TPWindow& window) +{ + if (window.is_empty()) { + os << "Window is empty!\n"; + } else { + os << "Window start: " << window.time_start << ", end: " << window.inputs.back().time_start; + os << ". Total of: " << window.adc_integral << " ADC counts with " << window.inputs.size() << " TPs.\n"; + os << window.channel_states.size() << " independent channels have hits.\n"; + } + return os; +} + +} // namespace triggeralgs diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/Hit.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/Hit.cpp new file mode 100644 index 0000000..2716c0b --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/Hit.cpp @@ -0,0 +1,83 @@ +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/Hit.hpp" + +#include + +namespace triggeralgs { +namespace dbscan { + +//====================================================================== +HitSet::HitSet() +{ + hits.reserve(10); +} + +//====================================================================== +void +HitSet::insert(Hit* h) +{ + // We're typically inserting hits at or near the end, so do a + // linear scan instead of full binary search. This turns out to be much + // faster in our case + auto it = hits.rbegin(); + while (it != hits.rend() && (*it)->time >= h->time) { + // Don't insert the hit if we already have it + if (*it == h) { + return; + } + ++it; + } + + if (it == hits.rend() || *it != h) { + hits.insert(it.base(), h); + } +} + +//====================================================================== +Hit::Hit(float _time, int _chan, const triggeralgs::TriggerPrimitive* _prim) +{ + reset(_time, _chan, _prim); +} + +//====================================================================== + +void +Hit::reset(float _time, int _chan, const triggeralgs::TriggerPrimitive* _prim) +{ + time=_time; + chan=_chan; + cluster=kUndefined; + connectedness=Connectedness::kUndefined; + neighbours.clear(); + if(_prim){ + primitive=*_prim; + } +} + +//====================================================================== + +// Return true if hit was indeed a neighbour +bool +Hit::add_potential_neighbour(Hit* other, float eps, int minPts) +{ + if (other != this && euclidean_distance_sqr(*this, *other) < eps*eps) { + neighbours.insert(other); + if (neighbours.size() + 1 >= minPts) { + connectedness = Connectedness::kCore; + } + // Neighbourliness is symmetric + other->neighbours.insert(this); + if (other->neighbours.size() + 1 >= minPts) { + other->connectedness = Connectedness::kCore; + } + return true; + } + return false; +} + +} +} +// Local Variables: +// mode: c++ +// c-basic-offset: 4 +// c-file-style: "linux" +// End: diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/Point.hpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/Point.hpp new file mode 100644 index 0000000..48d5793 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/Point.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace dbscan { + +struct Point +{ + int chan; + float time; +}; + +} diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/dbscan.cpp b/dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/dbscan.cpp new file mode 100644 index 0000000..bfc2df7 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/src/dbscan/dbscan.cpp @@ -0,0 +1,325 @@ +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/dbscan.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/dbscan/Hit.hpp" + +#include +#include + +namespace triggeralgs { +namespace dbscan { + +//====================================================================== +int +neighbours_sorted(const std::vector& hits, Hit& q, float eps, int minPts) +{ + int n = 0; + // Loop over the hits starting from the latest hit, since we will + // ~always be adding a hit at recent times + for (auto hit_it = hits.rbegin(); hit_it != hits.rend(); ++hit_it) { + if ((*hit_it)->time > q.time + eps) + continue; + if ((*hit_it)->time < q.time - eps) + break; + + if (q.add_potential_neighbour(*hit_it, eps, minPts)) + ++n; + } + return n; +} + +//====================================================================== +bool +Cluster::maybe_add_new_hit(Hit* new_hit, float eps, int minPts) +{ + // Should we add this hit? + bool do_add = false; + + // Hits earlier than new_hit time minus `eps` can't possibly be + // neighbours, so start the search there in the sorted list of hits in this + // cluster + auto begin_it = std::lower_bound( + hits.begin(), hits.end(), new_hit->time - eps, time_comp_lower); + + for (auto it = begin_it; it != hits.end(); ++it) { + Hit* h = *it; + if (h->add_potential_neighbour(new_hit, eps, minPts)) { + do_add = true; + if (h->neighbours.size() + 1 >= minPts) { + h->connectedness = Connectedness::kCore; + } else { + h->connectedness = Connectedness::kEdge; + } + } + } // end loop over hits in cluster + + if (do_add) { + add_hit(new_hit); + } + + return do_add; +} + +//====================================================================== +void +Cluster::add_hit(Hit* h) +{ + hits.insert(h); + h->cluster = index; + latest_time = std::max(latest_time, h->time); + if (h->connectedness == Connectedness::kCore && + (!latest_core_point || h->time > latest_core_point->time)) { + latest_core_point = h; + } +} + +//====================================================================== +void +Cluster::steal_hits(Cluster& other) +{ + // TODO: it might be faster to do some sort of explicit "merge" of the hits, + // eg: + // + // this->hits.insert(other hits); // Inserts at end + // std::inplace_merge(...) + // + // This might save some reallocations of the vector + for (auto h : other.hits) { + assert(h); + add_hit(h); + } + other.hits.clear(); + other.completeness = Completeness::kComplete; +} + +//====================================================================== +void +IncrementalDBSCAN::cluster_reachable(Hit* seed_hit, Cluster& cluster) +{ + // Loop over all neighbours (and the neighbours of core points, and so on) + std::vector seedSet(seed_hit->neighbours.begin(), + seed_hit->neighbours.end()); + + while (!seedSet.empty()) { + Hit* q = seedSet.back(); + seedSet.pop_back(); + // Change noise to a border point + if (q->connectedness == Connectedness::kNoise) { + cluster.add_hit(q); + } + + if (q->cluster != kUndefined) { + continue; + } + + cluster.add_hit(q); + + // If q is a core point, add its neighbours to the search list + if (q->neighbours.size() + 1 >= m_minPts) { + q->connectedness = Connectedness::kCore; + seedSet.insert( + seedSet.end(), q->neighbours.begin(), q->neighbours.end()); + } + } +} + +//====================================================================== +void +IncrementalDBSCAN::add_point(float time, float channel, std::vector* completed_clusters) +{ + Hit& new_hit=m_hit_pool[m_pool_end]; + new_hit.reset(time, channel); + ++m_pool_end; + if(m_pool_end==m_hit_pool.size()) m_pool_end=0; + add_hit(&new_hit, completed_clusters); +} + +//====================================================================== +void +IncrementalDBSCAN::add_primitive(const triggeralgs::TriggerPrimitive& prim, std::vector* completed_clusters) +{ + if(m_first_prim_time==0){ + m_first_prim_time=prim.time_start; + } + + Hit& new_hit=m_hit_pool[m_pool_end]; + new_hit.reset(1e-2*(prim.time_start-m_first_prim_time), prim.channel, &prim); + ++m_pool_end; + if(m_pool_end==m_hit_pool.size()) m_pool_end=0; + + add_hit(&new_hit, completed_clusters); +} + +//====================================================================== +void +IncrementalDBSCAN::add_hit(Hit* new_hit, std::vector* completed_clusters) +{ + // TODO: this should be a member variable, not a static, in case + // there are multiple IncrementalDBSCAN instances + static int next_cluster_index = 0; + + m_hits.push_back(new_hit); + m_latest_time = new_hit->time; + + // All the clusters that this hit neighboured. If there are + // multiple clusters neighbouring this hit, we'll merge them at + // the end + std::set clusters_neighbouring_hit; + + // Find all the hit's neighbours + neighbours_sorted(m_hits, *new_hit, m_eps, m_minPts); + + for (auto neighbour : new_hit->neighbours) { + if (neighbour->cluster != kUndefined && neighbour->cluster != kNoise && + neighbour->neighbours.size() + 1 >= m_minPts) { + // This neighbour is a core point in a cluster. Add the cluster to the list of + // clusters that will contain this hit + clusters_neighbouring_hit.insert(neighbour->cluster); + } + } + + if (clusters_neighbouring_hit.empty()) { + // This hit didn't match any existing cluster. See if we can + // make a new cluster out of it. Otherwise mark it as noise + + if (new_hit->neighbours.size() + 1 >= m_minPts) { + // std::cout << "New cluster starting at hit time " << new_hit->time << " with " << new_hit->neighbours.size() << " neighbours" << std::endl; + new_hit->connectedness = Connectedness::kCore; + auto new_it = m_clusters.emplace_hint( + m_clusters.end(), next_cluster_index, next_cluster_index); + Cluster& new_cluster = new_it->second; + new_cluster.completeness = Completeness::kIncomplete; + new_cluster.add_hit(new_hit); + next_cluster_index++; + cluster_reachable(new_hit, new_cluster); + } + else{ + // std::cout << "New hit time " << new_hit->time << " with " << new_hit->neighbours.size() << " neighbours is noise" << std::endl; + } + } else { + // This hit neighboured at least one cluster. Add the hit and + // its noise neighbours to the first cluster in the list, then + // merge the rest of the clusters into it + + auto index_it = clusters_neighbouring_hit.begin(); + + auto it = m_clusters.find(*index_it); + assert(it != m_clusters.end()); + Cluster& cluster = it->second; + // std::cout << "Adding hit time " << new_hit->time << " with " << new_hit->neighbours.size() << " neighbours to existing cluster" << std::endl; + cluster.add_hit(new_hit); + + // TODO: this seems wrong: we're adding this hit's neighbours + // to the cluster even if this hit isn't a core point, but if + // I wrap the whole thing in "if(new_hit is core)" then the + // results differ from classic DBSCAN + for (auto q : new_hit->neighbours) { + if (q->cluster == kUndefined || q->cluster == kNoise) { + // std::cout << " Adding hit time " << q->time << " to existing cluster" << std::endl; + cluster.add_hit(q); + } + // If the neighbouring hit q has exactly m_minPts + // neighbours, it must have become a core point by the + // addition of new_hit. Add q's neighbours to the cluster + if(q->neighbours.size() + 1 == m_minPts){ + for (auto r : q->neighbours) { + cluster.add_hit(r); + } + } + } + + + ++index_it; + + for (; index_it != clusters_neighbouring_hit.end(); ++index_it) { + + auto other_it = m_clusters.find(*index_it); + assert(other_it != m_clusters.end()); + Cluster& other_cluster = other_it->second; + cluster.steal_hits(other_cluster); + } + } + + // Last case: new_hit and its neighbour are both noise, but the + // addition of new_hit makes the neighbour a core point. So we + // start a new cluster at the neighbour, and walk out from there + for (auto& neighbour : new_hit->neighbours) { + if(neighbour->neighbours.size() + 1 >= m_minPts){ + // std::cout << "new_hit's neighbour at " << neighbour->time << " has " << neighbour->neighbours.size() << " neighbours, so is core" << std::endl; + if(neighbour->cluster==kNoise || neighbour->cluster==kUndefined){ + if(new_hit->cluster==kNoise || new_hit->cluster==kUndefined){ + auto new_it = m_clusters.emplace_hint( + m_clusters.end(), next_cluster_index, next_cluster_index); + Cluster& new_cluster = new_it->second; + new_cluster.completeness = Completeness::kIncomplete; + new_cluster.add_hit(neighbour); + next_cluster_index++; + cluster_reachable(neighbour, new_cluster); + } + } + } + else { + // std::cout << "new_hit's neighbour at " << neighbour->time << " has " << neighbour->neighbours.size() << " neighbours, so is NOT core" << std::endl; + } + } + + + // Delete any completed clusters from the list. Put them in the + // `completed_clusters` vector, if that vector was passed + auto clust_it = m_clusters.begin(); + while (clust_it != m_clusters.end()) { + Cluster& cluster = clust_it->second; + + if (cluster.latest_time < m_latest_time - m_eps) { + cluster.completeness = Completeness::kComplete; + } + + if (cluster.completeness == Completeness::kComplete) { + if(completed_clusters){ + // TODO: room for std::move here? + // + // Clusters that got merged into another cluster had + // their hits cleared, and were set kComplete, by + // steal_hits + if(cluster.hits.size()!=0){ + completed_clusters->push_back(cluster); + } + } + clust_it = m_clusters.erase(clust_it); + continue; + } else { + ++clust_it; + } + } +} + +void +IncrementalDBSCAN::trim_hits() +{ + // Find the earliest time of a hit in any cluster in the list (active or + // not) + float earliest_time = std::numeric_limits::max(); + + for (auto& cluster : m_clusters) { + earliest_time = + std::min(earliest_time, (*cluster.second.hits.begin())->time); + } + + // If there were no clusters, set the earliest_time to the latest time + // (otherwise it would still be FLOAT_MAX) + if (m_clusters.empty()) { + earliest_time = m_latest_time; + } + auto last_it = std::lower_bound(m_hits.begin(), + m_hits.end(), + earliest_time - 10 * m_eps, + time_comp_lower); + + m_hits.erase(m_hits.begin(), last_it); +} + +} +} +// Local Variables: +// mode: c++ +// c-basic-offset: 4 +// c-file-style: "linux" +// End: diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/test/CMakeLists.txt b/dunetrigger/TriggerSim/triggeralgs/v5/test/CMakeLists.txt new file mode 100644 index 0000000..9a402bc --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/test/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(test_factory test_factory.cxx) +target_link_libraries(test_factory PRIVATE triggeralgs trgdataformats::trgdataformats) +target_include_directories(test_factory PRIVATE ${BOOST_INCLUDE_DIRS}) +add_test(NAME factory COMMAND test_factory) diff --git a/dunetrigger/TriggerSim/triggeralgs/v5/test/test_factory.cxx b/dunetrigger/TriggerSim/triggeralgs/v5/test/test_factory.cxx new file mode 100644 index 0000000..00012e7 --- /dev/null +++ b/dunetrigger/TriggerSim/triggeralgs/v5/test/test_factory.cxx @@ -0,0 +1,46 @@ +/** + * @file test_factory.cxx + * + * This is part of the DUNE DAQ Application Framework, copyright 2023. + * Licensing/copyright details are in the COPYING file that you should have + * received with this code. + */ + +// NOLINTNEXTLINE(build/define_used) +#define BOOST_TEST_MODULE boost_test_macro_overview + +#include "triggeralgs/TriggerActivityFactory.hpp" +#include "triggeralgs/TriggerActivityMaker.hpp" + +#include + +#include +#include + +using namespace dunedaq; + +namespace triggeralgs { + +BOOST_AUTO_TEST_CASE(test_macro_overview) +{ + std::unique_ptr prescale_maker = TriggerActivityFactory::makeTAMaker("TAMakerPrescaleAlgorithm"); + + std::vector prescale_ta; + TriggerPrimitive some_tp; + for (int idx = 0; idx < 10; idx++) { + some_tp.time_start = idx; + some_tp.samples_to_peak = 1+idx; + some_tp.samples_over_threshold = 2; + some_tp.adc_integral = 1000+idx; + some_tp.adc_peak = 1000+idx; + some_tp.channel = 0+idx; + some_tp.detid = 0; + (*prescale_maker)(some_tp, prescale_ta); + } + + bool same_alg = (prescale_ta[0].algorithm == TriggerActivity::Algorithm::kPrescale); + + BOOST_TEST(same_alg); +} + +} /* namespace triggeralgs */ diff --git a/dunetrigger/channelmaps/OfflineTPCChannelMap.hpp b/dunetrigger/channelmaps/OfflineTPCChannelMap.hpp index a496d9c..a4119e4 100644 --- a/dunetrigger/channelmaps/OfflineTPCChannelMap.hpp +++ b/dunetrigger/channelmaps/OfflineTPCChannelMap.hpp @@ -48,6 +48,7 @@ class TPCChannelMap { // ignored in favour of the map LArsoft loads, and the argument is kept for // interface compatibility reasons. std::shared_ptr make_map(std::string const &plugin_name); +auto make_tpc_map = make_map; } // namespace dunedaq::detchannelmaps -#endif \ No newline at end of file +#endif From c0a3334e2171a574dfbe2fbe6cf3e324f2d96df7 Mon Sep 17 00:00:00 2001 From: James Shen Date: Mon, 21 Jul 2025 16:16:33 -0400 Subject: [PATCH 5/7] Allow TPM to make TPv2s --- .../TriggerPrimitiveMakerTPC_module.cc | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/dunetrigger/TriggerSim/TriggerPrimitiveMakerTPC_module.cc b/dunetrigger/TriggerSim/TriggerPrimitiveMakerTPC_module.cc index 7bec635..40b0ae0 100644 --- a/dunetrigger/TriggerSim/TriggerPrimitiveMakerTPC_module.cc +++ b/dunetrigger/TriggerSim/TriggerPrimitiveMakerTPC_module.cc @@ -1,4 +1,4 @@ -//////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// // Class: TriggerPrimitiveMakerTPC // Plugin Type: producer (Unknown Unknown) // File: TriggerPrimitiveMakerTPC_module.cc @@ -11,6 +11,7 @@ #include "detdataformats/DetID.hpp" #include "detdataformats/trigger/TriggerPrimitive.hpp" +#include "detdataformats/trigger/TriggerPrimitive2.hpp" #include "lardataobj/RawData/RDTimeStamp.h" #include "lardataobj/RawData/RawDigit.h" @@ -57,6 +58,7 @@ class dunetrigger::TriggerPrimitiveMakerTPC : public art::EDProducer { std::unique_ptr tpalg_; uint64_t default_timestamp_; int verbosity_; + int tp_version_; }; dunetrigger::TriggerPrimitiveMakerTPC::TriggerPrimitiveMakerTPC( @@ -66,11 +68,17 @@ dunetrigger::TriggerPrimitiveMakerTPC::TriggerPrimitiveMakerTPC( rawdigit_tag_(p.get("rawdigit_tag")), tpalg_{art::make_tool(p.get("tpalg"))}, default_timestamp_(p.get("default_timestamp", 0)), - verbosity_(p.get("verbosity", 0)) { + verbosity_(p.get("verbosity", 0)), + tp_version_(p.get("tp_version", 1)) { // Call appropriate produces<>() functions here. // Call appropriate consumes<>() for any products to be retrieved by this // module. - produces>(); + if (tp_version_ == 1) + produces>(); + else if (tp_version_ == 2) + produces>(); + else + std::cout << "BAD TP VERSION!" << std::endl; consumes>(rawdigit_tag_); consumes>(rawdigit_tag_); } @@ -115,8 +123,27 @@ void dunetrigger::TriggerPrimitiveMakerTPC::produce(art::Event &e) { (uint16_t)(dunedaq::detdataformats::DetID::Subdetector::kHD_TPC), this_timestamp, *tp_col_ptr); } - - e.put(std::move(tp_col_ptr)); + if (tp_version_ == 1) { + e.put(std::move(tp_col_ptr)); + } else if (tp_version_ == 2) { + auto tpv2_col_ptr = std::make_unique>(); + for (const auto& curr_tp : *tp_col_ptr) { + dunedaq::trgdataformats2::TriggerPrimitive curr_tpv2; + curr_tpv2.version = curr_tp.version; + // TODO: curr_tpv2.flag = ???; + curr_tpv2.detid = curr_tp.detid; + curr_tpv2.channel = curr_tp.channel; + curr_tpv2.samples_over_threshold = curr_tp.time_over_threshold / TPAlgTPCTool::ADC_SAMPLING_RATE_IN_DTS; + curr_tpv2.time_start = curr_tp.time_start; + curr_tpv2.samples_to_peak = (curr_tp.time_peak - curr_tp.time_start) / TPAlgTPCTool::ADC_SAMPLING_RATE_IN_DTS; + curr_tpv2.adc_integral = curr_tp.adc_integral; + curr_tpv2.adc_peak = curr_tp.adc_peak; + tpv2_col_ptr->push_back(std::move(curr_tpv2)); + } + e.put(std::move(tpv2_col_ptr)); + } else { + std::cout << "BAD TP VERSION!" << std::endl; + } } DEFINE_ART_MODULE(dunetrigger::TriggerPrimitiveMakerTPC) From cb2dfbbbef358af277ba4bfa4cd202050754af0b Mon Sep 17 00:00:00 2001 From: James Shen Date: Tue, 22 Jul 2025 16:26:55 -0400 Subject: [PATCH 6/7] V5 versions of TAM, TCM and TriggerAnaTree --- ...e_module.cc => TriggerAnaTreeV4_module.cc} | 34 +- .../TriggerAna/TriggerAnaTreeV5_module.cc | 508 ++++++++++++++++++ .../TriggerActivityMakerV5_module.cc | 291 ++++++++++ .../TriggerCandidateMakerV5_module.cc | 195 +++++++ 4 files changed, 1011 insertions(+), 17 deletions(-) rename dunetrigger/TriggerAna/{TriggerAnaTree_module.cc => TriggerAnaTreeV4_module.cc} (94%) create mode 100644 dunetrigger/TriggerAna/TriggerAnaTreeV5_module.cc create mode 100644 dunetrigger/TriggerSim/TriggerActivityMakerV5_module.cc create mode 100644 dunetrigger/TriggerSim/TriggerCandidateMakerV5_module.cc diff --git a/dunetrigger/TriggerAna/TriggerAnaTree_module.cc b/dunetrigger/TriggerAna/TriggerAnaTreeV4_module.cc similarity index 94% rename from dunetrigger/TriggerAna/TriggerAnaTree_module.cc rename to dunetrigger/TriggerAna/TriggerAnaTreeV4_module.cc index c58b6bf..d59285d 100644 --- a/dunetrigger/TriggerAna/TriggerAnaTree_module.cc +++ b/dunetrigger/TriggerAna/TriggerAnaTreeV4_module.cc @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////// -// Class: TriggerAnaTree +// Class: TriggerAnaTreeV4 // Plugin Type: analyzer (Unknown Unknown) -// File: TriggerAnaTree_module.cc +// File: TriggerAnaTreeV4_module.cc // // Generated at Fri Aug 30 14:50:19 2024 by jierans using cetskelgen // from cetlib version 3.18.02. @@ -37,10 +37,10 @@ using dunedaq::trgdataformats::TriggerCandidateData; using dunedaq::trgdataformats::TriggerPrimitive; namespace dunetrigger{ - class TriggerAnaTree; + class TriggerAnaTreeV4; } -class dunetrigger::TriggerAnaTree : public art::EDAnalyzer { +class dunetrigger::TriggerAnaTreeV4 : public art::EDAnalyzer { public: typedef struct ChannelInfo { unsigned int rop_id; @@ -48,15 +48,15 @@ class dunetrigger::TriggerAnaTree : public art::EDAnalyzer { unsigned int tpcset_id; } matching_info; - explicit TriggerAnaTree(fhicl::ParameterSet const &p); + explicit TriggerAnaTreeV4(fhicl::ParameterSet const &p); // The compiler-generated destructor is fine for non-base // classes without bare pointers or other resource use. // Plugins should not be copied or assigned. - TriggerAnaTree(TriggerAnaTree const &) = delete; - TriggerAnaTree(TriggerAnaTree &&) = delete; - TriggerAnaTree &operator=(TriggerAnaTree const &) = delete; - TriggerAnaTree &operator=(TriggerAnaTree &&) = delete; + TriggerAnaTreeV4(TriggerAnaTreeV4 const &) = delete; + TriggerAnaTreeV4(TriggerAnaTreeV4 &&) = delete; + TriggerAnaTreeV4 &operator=(TriggerAnaTreeV4 const &) = delete; + TriggerAnaTreeV4 &operator=(TriggerAnaTreeV4 &&) = delete; // Required functions. void beginJob() override; @@ -115,7 +115,7 @@ class dunetrigger::TriggerAnaTree : public art::EDAnalyzer { int ide_trkId, ide_origTrkId; }; -dunetrigger::TriggerAnaTree::TriggerAnaTree(fhicl::ParameterSet const &p) +dunetrigger::TriggerAnaTreeV4::TriggerAnaTreeV4(fhicl::ParameterSet const &p) : EDAnalyzer{p}, dump_tp(p.get("dump_tp")), dump_ta(p.get("dump_ta")), dump_tc(p.get("dump_tc")), dump_mctruths(p.get("dump_mctruths", true)), @@ -126,7 +126,7 @@ dunetrigger::TriggerAnaTree::TriggerAnaTree(fhicl::ParameterSet const &p) // More initializers here. {} -void dunetrigger::TriggerAnaTree::beginJob() { +void dunetrigger::TriggerAnaTreeV4::beginJob() { if (dump_mctruths) { mctruth_tree = tfs->make("mctruths", "mctruths"); mctruth_tree->Branch("Event", &fEventID, "Event/i"); @@ -181,7 +181,7 @@ void dunetrigger::TriggerAnaTree::beginJob() { } } -void dunetrigger::TriggerAnaTree::analyze(art::Event const &e) { +void dunetrigger::TriggerAnaTreeV4::analyze(art::Event const &e) { fRun = e.run(); fSubRun = e.subRun(); fEventID = e.id().event(); @@ -359,7 +359,7 @@ void dunetrigger::TriggerAnaTree::analyze(art::Event const &e) { } } -void dunetrigger::TriggerAnaTree::make_tp_tree_if_needed(std::string tag, bool assn) { +void dunetrigger::TriggerAnaTreeV4::make_tp_tree_if_needed(std::string tag, bool assn) { std::string map_tag = "tp/" + tag; if (!tree_map.count(map_tag)) { art::TFileDirectory tp_dir = @@ -395,7 +395,7 @@ void dunetrigger::TriggerAnaTree::make_tp_tree_if_needed(std::string tag, bool a } } -void dunetrigger::TriggerAnaTree::make_ta_tree_if_needed(std::string tag, bool assn) { +void dunetrigger::TriggerAnaTreeV4::make_ta_tree_if_needed(std::string tag, bool assn) { std::string map_tag = "ta/" + tag; if (!tree_map.count(map_tag)) { art::TFileDirectory ta_dir = @@ -430,7 +430,7 @@ void dunetrigger::TriggerAnaTree::make_ta_tree_if_needed(std::string tag, bool a } } -void dunetrigger::TriggerAnaTree::make_tc_tree_if_needed(std::string tag) { +void dunetrigger::TriggerAnaTreeV4::make_tc_tree_if_needed(std::string tag) { std::string map_tag = "tc/" + tag; if (!tree_map.count(map_tag)) { art::TFileDirectory tc_dir = @@ -456,7 +456,7 @@ void dunetrigger::TriggerAnaTree::make_tc_tree_if_needed(std::string tag) { } } -dunetrigger::TriggerAnaTree::ChannelInfo dunetrigger::TriggerAnaTree::get_channel_info_for_channel(geo::WireReadoutGeom const *geom, int channel) { +dunetrigger::TriggerAnaTreeV4::ChannelInfo dunetrigger::TriggerAnaTreeV4::get_channel_info_for_channel(geo::WireReadoutGeom const *geom, int channel) { readout::ROPID rop = geom->ChannelToROP(channel); ChannelInfo result; result.rop_id = rop.ROP; @@ -465,4 +465,4 @@ dunetrigger::TriggerAnaTree::ChannelInfo dunetrigger::TriggerAnaTree::get_channe return result; } -DEFINE_ART_MODULE(dunetrigger::TriggerAnaTree) +DEFINE_ART_MODULE(dunetrigger::TriggerAnaTreeV4) diff --git a/dunetrigger/TriggerAna/TriggerAnaTreeV5_module.cc b/dunetrigger/TriggerAna/TriggerAnaTreeV5_module.cc new file mode 100644 index 0000000..93f97b5 --- /dev/null +++ b/dunetrigger/TriggerAna/TriggerAnaTreeV5_module.cc @@ -0,0 +1,508 @@ +//////////////////////////////////////////////////////////////////////// +// Class: TriggerAnaTreeV5 +// Plugin Type: analyzer (Unknown Unknown) +// File: TriggerAnaTreeV5_module.cc +// +// Generated at Fri Aug 30 14:50:19 2024 by jierans using cetskelgen +// from cetlib version 3.18.02. +//////////////////////////////////////////////////////////////////////// + +#include "art/Framework/Core/EDAnalyzer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "art/Framework/Services/Registry/ServiceHandle.h" +#include "art_root_io/TFileDirectory.h" +#include "art_root_io/TFileService.h" +#include "canvas/Persistency/Common/FindManyP.h" +#include "canvas/Utilities/InputTag.h" +#include "fhiclcpp/ParameterSet.h" +#include "messagefacility/MessageLogger/MessageLogger.h" + +#include "detdataformats/trigger/TriggerActivityData2.hpp" +#include "detdataformats/trigger/TriggerCandidateData2.hpp" +#include "detdataformats/trigger/TriggerPrimitive2.hpp" + +#include "larcore/Geometry/WireReadout.h" +#include "larcoreobj/SimpleTypesAndConstants/readout_types.h" +#include "lardataobj/Simulation/SimChannel.h" +#include "nusimdata/SimulationBase/MCParticle.h" +#include "nusimdata/SimulationBase/MCTruth.h" +#include +#include +#include + +using dunedaq::trgdataformats2::TriggerActivityData; +using dunedaq::trgdataformats2::TriggerCandidateData; +using dunedaq::trgdataformats2::TriggerPrimitive; + +namespace dunetrigger { +class TriggerAnaTreeV5; +} + +class dunetrigger::TriggerAnaTreeV5 : public art::EDAnalyzer { +public: + struct ChannelInfo { + unsigned int rop_id; + int view; + unsigned int tpcset_id; + }; + + // Expand all the bitfields in TriggerPrimitive to full width, so that ROOT + // can safely use the address of the fields. + struct TriggerPrimitiveFullWidth { + // Metadata. + uint64_t version; + uint64_t flag; + uint64_t detid; + + // Physics data. + uint64_t channel; + + uint64_t samples_over_threshold; + uint64_t time_start; + uint64_t samples_to_peak; + + uint64_t adc_integral; + uint64_t adc_peak; + TriggerPrimitiveFullWidth& operator=(const TriggerPrimitive &tp) { + version = tp.version; + flag = tp.flag; + detid = tp.detid; + channel = tp.channel; + samples_over_threshold = tp.samples_over_threshold; + time_start = tp.time_start; + samples_to_peak = tp.samples_to_peak; + adc_integral = tp.adc_integral; + adc_peak = tp.adc_peak; + return *this; + } + }; + + explicit TriggerAnaTreeV5(fhicl::ParameterSet const &p); + // The compiler-generated destructor is fine for non-base + // classes without bare pointers or other resource use. + + // Plugins should not be copied or assigned. + TriggerAnaTreeV5(TriggerAnaTreeV5 const &) = delete; + TriggerAnaTreeV5(TriggerAnaTreeV5 &&) = delete; + TriggerAnaTreeV5 &operator=(TriggerAnaTreeV5 const &) = delete; + TriggerAnaTreeV5 &operator=(TriggerAnaTreeV5 &&) = delete; + + // Required functions. + void beginJob() override; + void analyze(art::Event const &e) override; + // void endJob() override; + +private: + art::ServiceHandle tfs; + std::map tree_map; + // buffers for writing to ROOT Trees + unsigned int fEventID; + int fRun; + int fSubRun; + int fAssnIdx; + + std::unordered_map trkId_to_truthBlockId; + std::map tp_bufs; + std::map tp_channel_info_bufs; + std::map ta_bufs; + std::map tc_bufs; + + bool dump_tp, dump_ta, dump_tc; + + void make_tp_tree_if_needed(std::string tag, bool assn = false); + void make_ta_tree_if_needed(std::string tag, bool assn = false); + void make_tc_tree_if_needed(std::string tag); + + ChannelInfo get_channel_info_for_channel(geo::WireReadoutGeom const *geom, + int channel); + + bool dump_mctruths; + TTree *mctruth_tree; + int mctruth_pdg; + std::string mctruth_process; + int mctruth_status, mctruth_id; + std::string mctruth_gen_name; + double mctruth_x, mctruth_y, mctruth_z; + double mctruth_Px, mctruth_Py, mctruth_Pz; + double mctruth_en; + + bool dump_mcparticles; + TTree *mcparticle_tree; + int mcparticle_pdg; + std::string mcparticle_process; + int mcparticle_status, mcparticle_trackid, mcparticle_truthid; + std::string mcparticle_gen_name; + double mcparticle_x, mcparticle_y, mcparticle_z; + double mcparticle_Px, mcparticle_Py, mcparticle_Pz; + double mcparticle_en; + + bool dump_simides; + std::string simchannel_tag; + TTree *simide_tree; + unsigned int sim_channel_id; + unsigned short tdc; + float ide_numElectrons, ide_energy, ide_x, ide_y, ide_z; + int ide_trkId, ide_origTrkId; +}; + +dunetrigger::TriggerAnaTreeV5::TriggerAnaTreeV5(fhicl::ParameterSet const &p) + : EDAnalyzer{p}, dump_tp(p.get("dump_tp")), + dump_ta(p.get("dump_ta")), dump_tc(p.get("dump_tc")), + dump_mctruths(p.get("dump_mctruths", true)), + dump_mcparticles(p.get("dump_mcparticles", true)), + dump_simides(p.get("dump_simides", true)), + simchannel_tag( + p.get("simchannel_tag", "tpcrawdecoder:simpleSC")) +// More initializers here. +{} + +void dunetrigger::TriggerAnaTreeV5::beginJob() { + if (dump_mctruths) { + mctruth_tree = tfs->make("mctruths", "mctruths"); + mctruth_tree->Branch("Event", &fEventID, "Event/i"); + mctruth_tree->Branch("Run", &fRun, "Run/i"); + mctruth_tree->Branch("SubRun", &fSubRun, "SubRun/i"); + mctruth_tree->Branch("block_id", &mctruth_id); + mctruth_tree->Branch("pdg", &mctruth_pdg); + mctruth_tree->Branch("generator_name", &mctruth_gen_name); + mctruth_tree->Branch("status_code", &mctruth_status); + mctruth_tree->Branch("x", &mctruth_x); + mctruth_tree->Branch("y", &mctruth_y); + mctruth_tree->Branch("z", &mctruth_z); + mctruth_tree->Branch("Px", &mctruth_Px); + mctruth_tree->Branch("Py", &mctruth_Py); + mctruth_tree->Branch("Pz", &mctruth_Pz); + mctruth_tree->Branch("en", &mctruth_en); + mctruth_tree->Branch("process", &mctruth_process); + } + if (dump_mcparticles) { + mcparticle_tree = tfs->make("mcparticles", "mcparticles"); + mcparticle_tree->Branch("Event", &fEventID, "Event/i"); + mcparticle_tree->Branch("Run", &fRun, "Run/i"); + mcparticle_tree->Branch("SubRun", &fSubRun, "SubRun/i"); + mcparticle_tree->Branch("pdg", &mcparticle_pdg); + mcparticle_tree->Branch("generator_name", &mcparticle_gen_name); + mcparticle_tree->Branch("status_code", &mcparticle_status); + mcparticle_tree->Branch("track_id", &mcparticle_trackid); + mcparticle_tree->Branch("truth_id", &mcparticle_truthid); + mcparticle_tree->Branch("x", &mcparticle_x); + mcparticle_tree->Branch("y", &mcparticle_y); + mcparticle_tree->Branch("z", &mcparticle_z); + mcparticle_tree->Branch("Px", &mcparticle_Px); + mcparticle_tree->Branch("Py", &mcparticle_Py); + mcparticle_tree->Branch("Pz", &mcparticle_Pz); + mcparticle_tree->Branch("en", &mcparticle_en); + mcparticle_tree->Branch("process", &mcparticle_process); + } + if (dump_simides) { + simide_tree = tfs->make("simides", "simides"); + simide_tree->Branch("Event", &fEventID, "Event/i"); + simide_tree->Branch("Run", &fRun, "Run/i"); + simide_tree->Branch("SubRun", &fSubRun, "SubRun/i"); + simide_tree->Branch("ChannelID", &sim_channel_id, "ChannelID/i"); + simide_tree->Branch("Timestamp", &tdc, "Timestamp/s"); + simide_tree->Branch("numElectrons", &ide_numElectrons, + "ide_numElectrons/i"); + simide_tree->Branch("Energy", &ide_energy, "ide_energy/F"); + simide_tree->Branch("x", &ide_x, "ide_x/F"); + simide_tree->Branch("y", &ide_y, "ide_y/F"); + simide_tree->Branch("z", &ide_z, "ide_z/F"); + simide_tree->Branch("trackID", &ide_trkId, "ide_trkId/I"); + simide_tree->Branch("origTrackID", &ide_origTrkId, "ide_origTrkId/I"); + } +} + +void dunetrigger::TriggerAnaTreeV5::analyze(art::Event const &e) { + fRun = e.run(); + fSubRun = e.subRun(); + fEventID = e.id().event(); + // get a service handle for geometry + geo::WireReadoutGeom const *geom = + &art::ServiceHandle()->Get(); + if (dump_mctruths) { + std::vector>> mctruthHandles = + e.getMany>(); + int truth_block_counter = 0; + trkId_to_truthBlockId.clear(); + for (auto const &mctruthHandle : mctruthHandles) { + std::string generator_name = + mctruthHandle.provenance()->inputTag().label(); + // NOTE: here we are making an assumption that the geant4 stage's process + // name is largeant. This should be safe mostly. + art::FindManyP assns(mctruthHandle, e, "largeant"); + for (size_t i = 0; i < mctruthHandle->size(); i++) { + const simb::MCTruth &truthblock = + *art::Ptr(mctruthHandle, i); + int nparticles = truthblock.NParticles(); + if (dump_mcparticles) { + std::vector> matched_mcparts = assns.at(i); + for (art::Ptr mcpart : matched_mcparts) { + trkId_to_truthBlockId[mcpart->TrackId()] = truth_block_counter; + } + } + for (int ipart = 0; ipart < nparticles; ipart++) { + const simb::MCParticle &part = truthblock.GetParticle(ipart); + mctruth_id = truth_block_counter; + mctruth_pdg = part.PdgCode(); + mctruth_gen_name = generator_name; + mctruth_status = part.StatusCode(); + mctruth_process = part.Process(); + mctruth_x = part.Vx(); + mctruth_y = part.Vy(); + mctruth_z = part.Vz(); + mctruth_Px = part.Px(); + mctruth_Py = part.Py(); + mctruth_Pz = part.Pz(); + mctruth_en = part.E(); + mctruth_tree->Fill(); + } + truth_block_counter++; + } + } + } + if (dump_mcparticles) { + std::vector>> mcparticleHandles = + e.getMany>(); + for (auto const &mcparticleHandle : mcparticleHandles) { + std::string generator_name = + mcparticleHandle.provenance()->inputTag().label(); + for (const simb::MCParticle &part : *mcparticleHandle) { + mcparticle_pdg = part.PdgCode(); + mcparticle_gen_name = generator_name; + mcparticle_status = part.StatusCode(); + mcparticle_trackid = part.TrackId(); + mcparticle_truthid = + dump_mctruths ? trkId_to_truthBlockId.at(part.TrackId()) : -1; + mcparticle_process = part.Process(); + mcparticle_x = part.Vx(); + mcparticle_y = part.Vy(); + mcparticle_z = part.Vz(); + mcparticle_Px = part.Px(); + mcparticle_Py = part.Py(); + mcparticle_Pz = part.Pz(); + mcparticle_en = part.E(); + mcparticle_tree->Fill(); + } + } + } + if (dump_simides) { + + auto simchannels = + e.getValidHandle>(simchannel_tag); + for (const sim::SimChannel &sc : *simchannels) { + sim_channel_id = sc.Channel(); + sim::SimChannel::TDCIDEs_t const &tdcidemap = sc.TDCIDEMap(); + for (const sim::TDCIDE &tdcide : tdcidemap) { + tdc = tdcide.first; + for (sim::IDE ide : tdcide.second) { + ide_numElectrons = ide.numElectrons; + ide_energy = ide.energy; + ide_x = ide.x; + ide_y = ide.y; + ide_z = ide.z; + ide_trkId = ide.trackID; + ide_origTrkId = ide.origTrackID; + simide_tree->Fill(); + } + } + } + } + if (dump_tp) { + std::vector>> tpHandles = + e.getMany>(); + for (auto const &tpHandle : tpHandles) { + std::string tag = tpHandle.provenance()->inputTag().encode(); + std::string map_tag = "tp/" + tag; + make_tp_tree_if_needed(tag); + for (const TriggerPrimitive &tp : *tpHandle) { + tp_bufs[map_tag] = tp; + tp_channel_info_bufs[map_tag] = + get_channel_info_for_channel(geom, tp.channel); + tree_map[map_tag]->Fill(); + } + } + } + + if (dump_ta) { + std::vector>> taHandles = + e.getMany>(); + for (auto const &taHandle : taHandles) { + art::FindManyP assns( + taHandle, e, taHandle.provenance()->moduleLabel()); + std::string tag = taHandle.provenance()->inputTag().encode(); + std::string map_tag = "ta/" + tag; + make_ta_tree_if_needed(tag); + for (unsigned int i = 0; i < taHandle->size(); i++) { + const TriggerActivityData &ta = + *art::Ptr(taHandle, i); + if (assns.isValid()) { + art::InputTag ta_input_tag = taHandle.provenance()->inputTag(); + std::string tpInTaTag = + art::InputTag(ta_input_tag.label(), + ta_input_tag.instance() + "inTAs", + ta_input_tag.process()) + .encode(); + std::string map_tpInTaTag = "tp/" + tpInTaTag; + make_tp_tree_if_needed(tpInTaTag, true); + fAssnIdx = i; + std::vector> matched_tps = assns.at(i); + for (art::Ptr tp : matched_tps) { + tp_bufs[map_tpInTaTag] = *tp; + tp_channel_info_bufs[map_tag] = + get_channel_info_for_channel(geom, tp->channel); + tree_map[map_tpInTaTag]->Fill(); + } + } + ta_bufs[map_tag] = ta; + tree_map[map_tag]->Fill(); + } + } + } + + if (dump_tc) { + std::vector>> tcHandles = + e.getMany>(); + for (auto const &tcHandle : tcHandles) { + art::FindManyP assns( + tcHandle, e, tcHandle.provenance()->moduleLabel()); + std::string tag = tcHandle.provenance()->inputTag().encode(); + std::string map_tag = "tc/" + tag; + make_tc_tree_if_needed(tag); + for (unsigned int i = 0; i < tcHandle->size(); i++) { + const TriggerCandidateData &tc = + *art::Ptr(tcHandle, i); + if (assns.isValid()) { + art::InputTag tc_input_tag = tcHandle.provenance()->inputTag(); + std::string taInTcTag = + art::InputTag(tc_input_tag.label(), + tc_input_tag.instance() + "inTCs", + tc_input_tag.process()) + .encode(); + std::string map_taInTcTag = "ta/" + taInTcTag; + make_ta_tree_if_needed(taInTcTag, true); + fAssnIdx = i; + std::vector> matched_tas = assns.at(i); + for (art::Ptr ta : matched_tas) { + ta_bufs[map_taInTcTag] = *ta; + tree_map[map_taInTcTag]->Fill(); + } + } + tc_bufs[map_tag] = tc; + tree_map[map_tag]->Fill(); + } + } + } +} + +void dunetrigger::TriggerAnaTreeV5::make_tp_tree_if_needed(std::string tag, + bool assn) { + std::string map_tag = "tp/" + tag; + if (!tree_map.count(map_tag)) { + art::TFileDirectory tp_dir = + tfs->mkdir("TriggerPrimitives", "Trigger Primitive Trees"); + std::cout << "Creating new TTree for " << tag << std::endl; + + // Replace ":" with "_" in TTree names so that they can be used in ROOT's + // intepreter + std::string tree_name = tag; + std::replace(tree_name.begin(), tree_name.end(), ':', '_'); + TTree *tree = tp_dir.make(tree_name.c_str(), tree_name.c_str()); + tree_map[map_tag] = tree; + TriggerPrimitiveFullWidth &tp = tp_bufs[map_tag]; + tree->Branch("Event", &fEventID, "Event/i"); + tree->Branch("Run", &fRun, "Run/i"); + tree->Branch("SubRun", &fSubRun, "SubRun/i"); + tree->Branch("version", &tp.version); + tree->Branch("flag", &tp.flag); + tree->Branch("time_start", &tp.time_start); + tree->Branch("sample_to_peak", &tp.samples_to_peak); + tree->Branch("samples_over_threshold", &tp.samples_over_threshold); + tree->Branch("channel", &tp.channel); + tree->Branch("adc_integral", &tp.adc_integral); + tree->Branch("adc_peak", &tp.adc_peak); + tree->Branch("detid", &tp.detid); + ChannelInfo &chinfo = tp_channel_info_bufs[map_tag]; + tree->Branch("ropid", &chinfo.rop_id, "ropid/i"); + tree->Branch("view", &chinfo.view, "view/I"); + tree->Branch("TPCSetID", &chinfo.tpcset_id, "TPCSetID/i"); + if (assn) + tree->Branch("TAnumber", &fAssnIdx, "TAnumber/I"); + } +} + +void dunetrigger::TriggerAnaTreeV5::make_ta_tree_if_needed(std::string tag, + bool assn) { + std::string map_tag = "ta/" + tag; + if (!tree_map.count(map_tag)) { + art::TFileDirectory ta_dir = + tfs->mkdir("TriggerActivities", "Trigger Activity Trees"); + std::cout << "Creating new TTree for " << tag << std::endl; + // Replace ":" with "_" in TTree names so that they can be used in ROOT's + // intepreter + std::string tree_name = tag; + std::replace(tree_name.begin(), tree_name.end(), ':', '_'); + TTree *tree = ta_dir.make(tree_name.c_str(), tree_name.c_str()); + tree_map[map_tag] = tree; + TriggerActivityData &ta = ta_bufs[map_tag]; + tree->Branch("Event", &fEventID, "Event/i"); + tree->Branch("Run", &fRun, "Run/i"); + tree->Branch("SubRun", &fSubRun, "SubRun/i"); + tree->Branch("version", &ta.version); + tree->Branch("time_start", &ta.time_start); + tree->Branch("time_end", &ta.time_end); + tree->Branch("time_peak", &ta.time_peak); + tree->Branch("time_activity", &ta.time_activity); + tree->Branch("channel_start", &ta.channel_start); + tree->Branch("channel_end", &ta.channel_end); + tree->Branch("channel_peak", &ta.channel_peak); + tree->Branch("adc_integral", &ta.adc_integral); + tree->Branch("adc_peak", &ta.adc_peak); + tree->Branch("detid", &ta.detid); + // HACK: assuming enums are ints here + tree->Branch("type", &ta.type, "type/I"); + tree->Branch("algorithm", &ta.algorithm, "algorithm/I"); + if (assn) + tree->Branch("TCnumber", &fAssnIdx, "TCnumber/I"); + } +} + +void dunetrigger::TriggerAnaTreeV5::make_tc_tree_if_needed(std::string tag) { + std::string map_tag = "tc/" + tag; + if (!tree_map.count(map_tag)) { + art::TFileDirectory tc_dir = + tfs->mkdir("TriggerCandidates", "Trigger Candidate Trees"); + std::cout << "Creating new TTree for " << tag << std::endl; + // Replace ":" with "_" in TTree names so that they can be used in ROOT's + // intepreter + std::string tree_name = tag; + std::replace(tree_name.begin(), tree_name.end(), ':', '_'); + TTree *tree = tc_dir.make(tree_name.c_str(), tree_name.c_str()); + tree_map[map_tag] = tree; + TriggerCandidateData &tc = tc_bufs[map_tag]; + tree->Branch("Event", &fEventID, "Event/i"); + tree->Branch("Run", &fRun, "Run/i"); + tree->Branch("SubRun", &fSubRun, "SubRun/i"); + tree->Branch("version", &tc.version); + tree->Branch("time_start", &tc.time_start); + tree->Branch("time_end", &tc.time_end); + tree->Branch("time_candidate", &tc.time_candidate); + tree->Branch("detid", &tc.detid); + tree->Branch("type", &tc.type, "type/I"); + tree->Branch("algorithm", &tc.algorithm, "algorithm/I"); + } +} + +dunetrigger::TriggerAnaTreeV5::ChannelInfo +dunetrigger::TriggerAnaTreeV5::get_channel_info_for_channel( + geo::WireReadoutGeom const *geom, int channel) { + readout::ROPID rop = geom->ChannelToROP(channel); + ChannelInfo result; + result.rop_id = rop.ROP; + result.tpcset_id = rop.asTPCsetID().TPCset; + result.view = geom->View(rop); + return result; +} + +DEFINE_ART_MODULE(dunetrigger::TriggerAnaTreeV5) diff --git a/dunetrigger/TriggerSim/TriggerActivityMakerV5_module.cc b/dunetrigger/TriggerSim/TriggerActivityMakerV5_module.cc new file mode 100644 index 0000000..7de2b0a --- /dev/null +++ b/dunetrigger/TriggerSim/TriggerActivityMakerV5_module.cc @@ -0,0 +1,291 @@ +//////////////////////////////////////////////////////////////////////// +// Class: TriggerActivityMakerV5 +// Plugin Type: producer (Unknown Unknown) +// File: TriggerActivityMakerV5_module.cc +//////////////////////////////////////////////////////////////////////// + +#include "art/Framework/Core/EDProducer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "art/Persistency/Common/PtrMaker.h" +#include "canvas/Persistency/Common/Assns.h" +#include "canvas/Persistency/Common/PtrVector.h" +#include "canvas/Utilities/InputTag.h" +#include "fhiclcpp/ParameterSet.h" +#include "larcore/Geometry/WireReadout.h" +#include "larcoreobj/SimpleTypesAndConstants/readout_types.h" +#include "messagefacility/MessageLogger/MessageLogger.h" + +#include "detdataformats/trigger/TriggerActivityData2.hpp" + +#include "dunetrigger/TriggerSim/Verbosity.hh" + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivity.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerActivityFactory.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerPrimitive.hpp" + +#include +#include + +#include +#include +#include +#include + +namespace dunedaq::trgdataformats2 { +bool operator<(const TriggerPrimitive &tp1, const TriggerPrimitive &tp2) { + return std::tie(tp1.time_start, tp1.channel) < + std::tie(tp2.time_start, tp2.channel); +} + +bool operator==(const TriggerPrimitive &tp1, const TriggerPrimitive &tp2) { + return (tp1.detid == tp2.detid && tp1.channel == tp2.channel && + tp1.time_start == tp2.time_start && + tp1.samples_to_peak == tp2.samples_to_peak && + tp1.adc_integral == tp2.adc_integral); +} + +} // namespace dunedaq::trgdataformats2 +namespace dunetrigger { +class TriggerActivityMakerV5; +typedef std::pair TAMakerScopeID_t; +typedef std::pair TriggerPrimitiveIdx; +using dunedaq::trgdataformats2::TriggerActivityData; +using triggeralgs::TriggerPrimitive; + +std::ostream &operator<<(std::ostream &os, + const dunetrigger::TAMakerScopeID_t &scope) { + return (os << scope.first << " P:" << scope.second); +} + +static TAMakerScopeID_t getTAScopeID(readout::ROPID &ropid, + geo::WireReadoutGeom const &geom) { + TAMakerScopeID_t result = {ropid.asTPCsetID(), // APA is a TPCSet + geom.View(ropid)}; + return result; +} + +} // namespace dunetrigger + +class dunetrigger::TriggerActivityMakerV5 : public art::EDProducer { +public: + explicit TriggerActivityMakerV5(fhicl::ParameterSet const &p); + // Plugins should not be copied or assigned. + TriggerActivityMakerV5(TriggerActivityMakerV5 const &) = delete; + TriggerActivityMakerV5(TriggerActivityMakerV5 &&) = delete; + TriggerActivityMakerV5 &operator=(TriggerActivityMakerV5 const &) = delete; + TriggerActivityMakerV5 &operator=(TriggerActivityMakerV5 &&) = delete; + + void beginJob() override; + void produce(art::Event &e) override; + +private: + // fields for job configuration + std::string algname; + fhicl::ParameterSet algconfig_plane0; + fhicl::ParameterSet algconfig_plane1; + fhicl::ParameterSet algconfig_plane2; + fhicl::ParameterSet algconfig_plane3; + art::InputTag tp_tag; + + std::vector channel_mask; + + int verbosity; + bool flush; + + // Factory instance to spin up algorithms + std::shared_ptr< + triggeralgs::AbstractFactory> + tf = triggeralgs::TriggerActivityFactory::get_instance(); + + std::map> + maker_per_plane; + + static nlohmann::json get_alg_config(fhicl::ParameterSet &pset_config) { + nlohmann::json algconfig; + for (auto k : pset_config.get_all_keys()) { + try { + algconfig[k] = pset_config.get(k); + } catch (const fhicl::exception &e) { + try { + // If false, try retrieving the parameter as a boolean + algconfig[k] = pset_config.get(k); + } catch (const fhicl::exception &e) { + std::cerr << "Error: FHiCL parameter is neither an int nor a bool in " + "the FHiCL file. \n"; + } + } + } + return algconfig; + } +}; + +dunetrigger::TriggerActivityMakerV5::TriggerActivityMakerV5( + fhicl::ParameterSet const &p) + : EDProducer{p}, algname(p.get("algorithm")), + algconfig_plane0(p.get("algconfig_plane0")), + algconfig_plane1(p.get("algconfig_plane1")), + algconfig_plane2(p.get("algconfig_plane2")), + algconfig_plane3(p.get("algconfig_plane3", {})), + tp_tag(p.get("tp_tag")), + channel_mask(p.get>( + "channel_mask", std::vector{})), + verbosity(p.get("verbosity", 1)), + flush(p.get("flush", false)) { + produces>(); + produces>(); + consumes>(tp_tag); +} + +void dunetrigger::TriggerActivityMakerV5::beginJob() { + if (verbosity >= Verbosity::kInfo) { + std::cout << "Masked Channels:"; + for (raw::ChannelID_t c : channel_mask) { + std::cout << " " << c; + if (!channel_mask.empty() && c != channel_mask.back()) { + std::cout << ","; + } + } + std::cout << std::endl; + } +} + +void dunetrigger::TriggerActivityMakerV5::produce(art::Event &e) { + geo::WireReadoutGeom const *geom = + &art::ServiceHandle()->Get(); + + // unique ptrs to vectors for associations + auto ta_vec_ptr = std::make_unique>(); + auto tp_vec_ptr = std::make_unique>(); + auto tp_in_tas_assn_ptr = + std::make_unique>(); + + // ptrmaker to make an art::ptr for the associations + art::PtrMaker taPtrMaker{e}; + + auto tpHandle = e.getValidHandle>(tp_tag); + std::vector tp_vec = *tpHandle; + + // Keep track of the original index of the TPs in order to make associations + // later. + std::map> tp_by_plane; + for (size_t i = 0; i < tp_vec.size(); ++i) { + readout::ROPID rop = geom->ChannelToROP(tp_vec.at(i).channel); + TAMakerScopeID_t scope = getTAScopeID(rop, *geom); + tp_by_plane[scope].push_back(std::make_pair(i, tp_vec.at(i))); + } + + // now we process each ROP + for (auto &tps : tp_by_plane) { + if (verbosity >= Verbosity::kInfo) { + std::cout << "Creating Maker on Plane " << tps.first << std::endl; + } + maker_per_plane[tps.first] = tf->build_maker(algname); + // make the algorithm here so that we reset the internal state for each ROP + // - since I believe those are independent for the TAMaker + std::shared_ptr alg = + maker_per_plane[tps.first]; + + if (!alg) { + throw "Invalid Algorithm!"; + } + + // get the APA from the ROP we are on + unsigned int plane = tps.first.second; + nlohmann::json this_algconfig; + switch (plane) { + case 0: + this_algconfig = get_alg_config(algconfig_plane0); + break; + case 1: + this_algconfig = get_alg_config(algconfig_plane1); + break; + case 2: + this_algconfig = get_alg_config(algconfig_plane2); + break; + case 3: + this_algconfig = get_alg_config(algconfig_plane3); + break; + default: + this_algconfig = get_alg_config(algconfig_plane0); + break; + } + alg->configure(this_algconfig); + std::sort(tps.second.begin(), tps.second.end()); + std::vector created_tas = {}; + + // and now loop through the TPs and create TAs + for (auto &tp : tps.second) { + // check that the tp is not in the channel mask + if (std::find(channel_mask.begin(), channel_mask.end(), + tp.second.channel) == channel_mask.end()) { + (*alg)(tp.second, created_tas); + } else if (verbosity >= Verbosity::kDebug) { + std::cout << "Ignoring Masked TP on channel: " << tp.second.channel + << std::endl; + } + } + // TPs in window will only be evaluated once an out-of-window TA is seen by + // the TAMaker. This would result in the last TA in the event being missing, + // and TAs being written to the wrong event. Avoid this by adding a dummy tp + // with infinite time to force a window evaluation. + if (flush) { + TriggerPrimitive dummy_tp; + (*alg)(dummy_tp, created_tas); + } + + if (verbosity >= Verbosity::kInfo && created_tas.size() > 0) { + std::cout << "Created " << created_tas.size() << " TAs on ROP " + << tps.first << std::endl; + } + + // to make the associations we have to use the idx we created earlier + // BUT the input TA only has a list of the base objects in it + // so we need to search through it and then get out our object with the + // index intact to make the association + for (auto const &out_ta : created_tas) { + // now we find the TPs which are in the output TA and create the + // associations + auto const taPtr = taPtrMaker(ta_vec_ptr->size()); + + ta_vec_ptr->emplace_back(out_ta); + + // now loop through each TP in the TA to handle associations + art::PtrVector tp_in_ta_ptrs; + for (auto &in_tp : out_ta.inputs) { + // get an iterator to matching TPs with find_if + std::vector::iterator tp_it = std::find_if( + tps.second.begin(), tps.second.end(), + [&](TriggerPrimitiveIdx const &tp) { return tp.second == in_tp; }); + if (tp_it == tps.second.end()) + std::cout + << "WARNING: TP recorded in TA is not found in the list of TPs!!!" + << std::endl; + while (tp_it != tps.second.end()) { + // push back an art::Ptr pointing to the proper index in the vector + // of input TPs + tp_in_ta_ptrs.push_back( + art::Ptr(tpHandle, tp_it->first)); + // get an iterator to the next (if any) matching TP + tp_it = std::find_if(++tp_it, tps.second.end(), + [&](TriggerPrimitiveIdx const &tp) { + return tp.second == in_tp; + }); + if (tp_it != tps.second.end()) + std::cout << "WARNING: More than one match found for TP recorded " + "in TA. Likely there's a duplicate in the TP list, or " + "operator== is inadequate." + << std::endl; + } + } + // add the associations to the tp_in_ta assoc + tp_in_tas_assn_ptr->addMany(taPtr, tp_in_ta_ptrs); + } + } + // Add to event + e.put(std::move(ta_vec_ptr)); + e.put(std::move(tp_in_tas_assn_ptr)); +} + +DEFINE_ART_MODULE(dunetrigger::TriggerActivityMakerV5) diff --git a/dunetrigger/TriggerSim/TriggerCandidateMakerV5_module.cc b/dunetrigger/TriggerSim/TriggerCandidateMakerV5_module.cc new file mode 100644 index 0000000..f5bdcca --- /dev/null +++ b/dunetrigger/TriggerSim/TriggerCandidateMakerV5_module.cc @@ -0,0 +1,195 @@ +//////////////////////////////////////////////////////////////////////// +// Class: TriggerCandidateMakerV5 +// Plugin Type: producer (Unknown Unknown) +// File: TriggerCandidateMakerV5_module.cc +//////////////////////////////////////////////////////////////////////// + +#include "art/Framework/Core/EDProducer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "art/Framework/Principal/Run.h" +#include "art/Framework/Principal/SubRun.h" +#include "art/Framework/Services/Registry/ServiceHandle.h" +#include "art/Persistency/Common/PtrMaker.h" +#include "canvas/Persistency/Common/Assns.h" +#include "canvas/Persistency/Common/PtrVector.h" +#include "canvas/Persistency/Common/types.h" +#include "canvas/Utilities/InputTag.h" +#include "fhiclcpp/ParameterSet.h" +#include "messagefacility/MessageLogger/MessageLogger.h" + +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidate.hpp" +#include "dunetrigger/TriggerSim/triggeralgs/v5/include/triggeralgs/TriggerCandidateFactory.hpp" + +#include "detdataformats/trigger/TriggerActivityData2.hpp" +#include "detdataformats/trigger/TriggerCandidateData2.hpp" + +#include "dunetrigger/TriggerSim/Verbosity.hh" + +#include + +#include +#include +#include +#include + +namespace dunedaq::trgdataformats2 { +bool operator==(const TriggerActivityData &ta1, + const TriggerActivityData &ta2) { + return (ta1.detid == ta2.detid && ta1.channel_peak == ta2.channel_peak && + ta1.time_peak == ta2.time_peak && + ta1.adc_integral == ta2.adc_integral); +} +bool operator<(const TriggerActivityData &ta1, const TriggerActivityData &ta2) { + return std::tie(ta1.time_start, ta1.channel_start) < + std::tie(ta2.time_start, ta2.channel_start); +} + +} // namespace dunedaq::trgdataformats2 + +namespace dunetrigger { +class TriggerCandidateMakerV5; +using dunedaq::trgdataformats2::TriggerActivityData; +using dunedaq::trgdataformats2::TriggerCandidateData; +typedef std::pair TriggerActivityIdx; + +} // namespace dunetrigger + +class dunetrigger::TriggerCandidateMakerV5 : public art::EDProducer { +public: + explicit TriggerCandidateMakerV5(fhicl::ParameterSet const &p); + + // Plugins should not be copied or assigned. + TriggerCandidateMakerV5(TriggerCandidateMakerV5 const &) = delete; + TriggerCandidateMakerV5(TriggerCandidateMakerV5 &&) = delete; + TriggerCandidateMakerV5 &operator=(TriggerCandidateMakerV5 const &) = delete; + TriggerCandidateMakerV5 &operator=(TriggerCandidateMakerV5 &&) = delete; + + void beginJob() override; + void produce(art::Event &e) override; + +private: + art::InputTag ta_tag; + std::string algname; + fhicl::ParameterSet algconfig; + + std::shared_ptr< + triggeralgs::AbstractFactory> + alg_factory = triggeralgs::TriggerCandidateFactory::get_instance(); + std::unique_ptr alg; + + int verbosity; +}; + +dunetrigger::TriggerCandidateMakerV5::TriggerCandidateMakerV5( + fhicl::ParameterSet const &p) + : EDProducer{p}, ta_tag(p.get("ta_tag")), + algname(p.get("algorithm")), + algconfig(p.get("algconfig")), + verbosity(p.get("verbosity", 0)) { + + consumes>(ta_tag); + produces>(); + produces>(); +} + +void dunetrigger::TriggerCandidateMakerV5::beginJob() { + // build alg using the factory + alg = alg_factory->build_maker(algname); + + // parse the parameterset as json + nlohmann::json alg_json; + for (auto &k : algconfig.get_all_keys()) { + try { + alg_json[k] = algconfig.get(k); + } catch (const fhicl::exception &e) { + try { + // If false, try retrieving the parameter as a boolean + alg_json[k] = algconfig.get(k); + } catch (const fhicl::exception &e) { + std::cerr << "Error: FHiCL parameter is neither an int nor a bool in " + "the FHiCL file. \n"; + } + } + } + + // and pass that on to the trigger algorithm + alg->configure(alg_json); +} + +void dunetrigger::TriggerCandidateMakerV5::produce(art::Event &e) { + // get a handle on the TAs and dereference it + auto ta_handle = e.getValidHandle>(ta_tag); + std::vector ta_vec = *ta_handle; + + // some unique pointers to new vectors for the data products + auto tc_vec_ptr = std::make_unique>(); + auto ta_in_tc_assn_ptr = + std::make_unique>(); + + art::PtrMaker tc_ptr_maker{e}; + + // create a vector of inputs with the 'file' index of the TA + std::vector input_tas; //(ta_vec.size()); + for (size_t i = 0; i < ta_vec.size(); ++i) { + input_tas.push_back(TriggerActivityIdx(i, ta_vec.at(i))); + } + + std::sort(input_tas.begin(), input_tas.end()); + + // create a vector of online TCs for the online algorithm to store it's + // outputs in + std::vector produced_tcs = {}; + + // process the input TAs + for (const auto &ta_indexed : input_tas) { + TriggerActivityData ta_data = ta_indexed.second; + triggeralgs::TriggerActivity curr_ta; + static_cast(curr_ta) = ta_data; + (*alg)(curr_ta, produced_tcs); + } + + // now we need to handle the associations + for (auto out_tc : produced_tcs) { + // make an art pointer to the tc vector + auto const tcPtr = tc_ptr_maker(tc_vec_ptr->size()); + tc_vec_ptr->emplace_back(out_tc); + + // and now get the TAs out of the processed TC + art::PtrVector tas_in_tc_ptr; + for (const TriggerActivityData &in_ta : out_tc.inputs) { + + std::vector::iterator ta_it = std::find_if( + input_tas.begin(), input_tas.end(), + [&](const TriggerActivityIdx &curr_ta) { return curr_ta.second == in_ta; }); + // stop when there are no more matches + while (ta_it != input_tas.end()) { + tas_in_tc_ptr.push_back( + art::Ptr(ta_handle, ta_it->first)); + // get an iterator pointing to the next match + ta_it = std::find_if(++ta_it, input_tas.end(), + [&](const TriggerActivityIdx &curr_ta) { + return curr_ta.second == in_ta; + }); + } + + // print a debug message if we can't find and associated TAs + if (tas_in_tc_ptr.empty() && verbosity >= Verbosity::kDebug) { + std::cout << "No associated TAs found for TC!" << std::endl; + } + } + // add the associations + ta_in_tc_assn_ptr->addMany(tcPtr, tas_in_tc_ptr); + } + + if (verbosity >= Verbosity::kInfo) { + std::cout << "Created " << produced_tcs.size() << " TCs" << std::endl; + } + + // move the produced things onto the event + e.put(std::move(tc_vec_ptr)); + e.put(std::move(ta_in_tc_assn_ptr)); +} + +DEFINE_ART_MODULE(dunetrigger::TriggerCandidateMakerV5) From d27e9b31a7a6b904f9591f6d3d5ad01fe8202645 Mon Sep 17 00:00:00 2001 From: James Shen Date: Tue, 22 Jul 2025 16:27:10 -0400 Subject: [PATCH 7/7] minimal test configs for v5 --- .../TriggerAna/fcl/triggerana_tree.fcl | 14 ++++++- dunetrigger/TriggerSim/fcl/triggersim.fcl | 14 ++++++- .../TriggerSim/fcl/triggersim_makers.fcl | 41 +++++++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/dunetrigger/TriggerAna/fcl/triggerana_tree.fcl b/dunetrigger/TriggerAna/fcl/triggerana_tree.fcl index 5dd70ba..2c1e665 100644 --- a/dunetrigger/TriggerAna/fcl/triggerana_tree.fcl +++ b/dunetrigger/TriggerAna/fcl/triggerana_tree.fcl @@ -16,7 +16,7 @@ outputs_triggerana_tree.out1.fileName: "triggerAnaTree.root" triggerAnaTree_dumpAll: { - module_type: TriggerAnaTree + module_type: TriggerAnaTreeV4 dump_tp: true dump_ta: true dump_tc: true @@ -29,6 +29,10 @@ triggerAnaTree_dumpAll: simchannel_tag: "tpcrawdecoder:simpleSC" } +triggerAnaTree_dumpAll_v5: { + @table::triggerAnaTree_dumpAll + module_type: TriggerAnaTreeV5 +} ## Basic example of a physics configuration, better to create your own physics_triggerana_tree_simpleThr_simpleWin_simpleWin: { @@ -50,4 +54,12 @@ physics_triggerana_tree_simpleThr_simpleWin_simpleWin: { end_paths: [ stream1, ana ] } +physics_triggerana_tree_simpleThr_simpleWin_simpleWin_v5: { + @table::physics_triggerana_tree_simpleThr_simpleWin_simpleWin + producers: @local::producers_triggersim_simpleThr_simpleWin_simpleWin_v5 + analyzers: { + triggerAnaDumpAll: @local::triggerAnaTree_dumpAll_v5 + } +} + END_PROLOG diff --git a/dunetrigger/TriggerSim/fcl/triggersim.fcl b/dunetrigger/TriggerSim/fcl/triggersim.fcl index 43a1c7e..fffe438 100644 --- a/dunetrigger/TriggerSim/fcl/triggersim.fcl +++ b/dunetrigger/TriggerSim/fcl/triggersim.fcl @@ -39,6 +39,13 @@ producers_triggersim_simpleThr_simpleWin_simpleWin: { tcmakerTPC: @local::tcmakerTPC_ADCSimpleWindow } +# the simplest configurations are here as default +producers_triggersim_simpleThr_simpleWin_simpleWin_v5: { + tpmakerTPC: @local::tpmakerTPC_ADCSimpleThreshold_v5 + tamakerTPC: @local::tamakerTPC_ADCSimpleWindow_v5 + tcmakerTPC: @local::tcmakerTPC_ADCSimpleWindow_v5 +} + # this does not have analyzers! Add them physics_triggersim_simpleThr_simpleWin_simpleWin: { producers: @local::producers_triggersim_simpleThr_simpleWin_simpleWin @@ -48,4 +55,9 @@ physics_triggersim_simpleThr_simpleWin_simpleWin: { end_paths: [ stream1 ] } -END_PROLOG \ No newline at end of file +physics_triggersim_simpleThr_simpleWin_simpleWin_v5: { + @table::physics_triggersim_simpleThr_simpleWin_simpleWin + producers: @local::producers_triggersim_simpleThr_simpleWin_simpleWin_v5 +} + +END_PROLOG diff --git a/dunetrigger/TriggerSim/fcl/triggersim_makers.fcl b/dunetrigger/TriggerSim/fcl/triggersim_makers.fcl index 703a140..b4d1e01 100644 --- a/dunetrigger/TriggerSim/fcl/triggersim_makers.fcl +++ b/dunetrigger/TriggerSim/fcl/triggersim_makers.fcl @@ -22,6 +22,20 @@ tpmakerTPC_ADCSimpleThreshold: } } +tpmakerTPC_ADCSimpleThreshold_v5: + { + module_type: TriggerPrimitiveMakerTPC + rawdigit_tag: "tpcrawdecoder:daq" + tp_version: 2 + tpalg: { + tool_type: TPAlgTPCSimpleThreshold + threshold_tpg_plane0: -1 + threshold_tpg_plane1: -1 + threshold_tpg_plane2: 60 + verbosity: 0 + } + } + #====================================================================== # TA makers @@ -63,6 +77,23 @@ tamakerTPC_ADCSimpleWindow: verbosity: 1 } +tamakerTPC_ADCSimpleWindow_v5: + { + module_type: TriggerActivityMakerV5 + tp_tag: "tpmakerTPC" + # simple window, see trgdataformats/include/trgdataformats/TriggerActivityData.hpp + algorithm: "TAMakerADCSimpleWindowAlgorithm" + algconfig_plane0: @local::ta_algconfig_simplewindow # induction 1 + algconfig_plane1: @local::ta_algconfig_simplewindow # induction 2 + algconfig_plane2: @local::ta_algconfig_simplewindow # collection facing one side (readout differentiates) + algconfig_plane3: @local::ta_algconfig_simplewindow # collection facing the other side (readout differentiates) + nmodules: @local::nmodules_protodunehd # just a default + mergecollwires: true + flush: true + prescale: 1 + print_tp_info: false + verbosity: 1 + } #====================================================================== # TC makers @@ -97,4 +128,14 @@ tcmakerTPC_ADCSimpleWindow: verbosity: 1 } +tcmakerTPC_ADCSimpleWindow_v5: + { + module_type: TriggerCandidateMakerV5 + ta_tag: "tamakerTPC" + algorithm: "TCMakerADCSimpleWindowAlgorithm" + algconfig: @local::tcconfig_simplewindow + multiplicity: 1 # keep? + verbosity: 1 + } + END_PROLOG