Line data Source code
1 : /**
2 : * @file TAMakerProtoDUNEBSMWindowAlgorithm.cpp
3 : *
4 : * This is part of the DUNE DAQ Application Framework, copyright 2021.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 :
9 : #include "triggeralgs/ProtoDUNEBSMWindow/TAMakerProtoDUNEBSMWindowAlgorithm.hpp"
10 :
11 : #include "TRACE/trace.h"
12 : #define TRACE_NAME "TAMakerProtoDUNEBSMWindowAlgorithm"
13 :
14 : #include <vector>
15 : #include <chrono>
16 :
17 : using namespace triggeralgs;
18 : using Logging::TLVL_DEBUG_ALL;
19 : using Logging::TLVL_DEBUG_HIGH;
20 : using Logging::TLVL_DEBUG_LOW;
21 : using Logging::TLVL_IMPORTANT;
22 :
23 : void
24 0 : TAMakerProtoDUNEBSMWindowAlgorithm::process(const TriggerPrimitive& input_tp, std::vector<TriggerActivity>& output_ta)
25 : {
26 :
27 0 : if(m_current_window.is_empty()){
28 0 : m_current_window.reset(input_tp);
29 0 : m_last_pred_time = input_tp.time_start;
30 0 : m_primitive_count++;
31 : // first time operator is called set ROP first and last channel
32 0 : unsigned int detelement = channelMap->get_element_id_from_offline_channel(input_tp.channel);
33 0 : unsigned int plane = channelMap->get_plane_from_offline_channel(input_tp.channel);
34 :
35 0 : PlaneInfo plane_info = m_det_plane_map.get_plane_info(m_channel_map_name, detelement, plane);
36 0 : m_first_channel = static_cast<channel_t>(plane_info.min_channel);
37 0 : channel_t n_channels_on_plane = static_cast<channel_t>(plane_info.n_channels);
38 :
39 : // If we are in PD-VD use 'effective' channel mapping for CRPs
40 0 : if (m_pdvd_map) {
41 0 : m_pdvd_eff_channel_mapper = std::make_unique<PDVDEffectiveChannelMap>(plane_info.min_channel, plane_info.n_channels);
42 :
43 0 : m_first_channel = m_pdvd_eff_channel_mapper->remapCollectionPlaneChannel(m_first_channel);
44 0 : m_last_channel = m_first_channel + m_pdvd_eff_channel_mapper->getNEffectiveChannels();
45 0 : m_chan_bin_length = m_pdvd_eff_channel_mapper->getNEffectiveChannels() / m_num_chanbins;
46 : } else { // still in PD-HD, so don't need effective channel
47 0 : m_last_channel = m_first_channel + n_channels_on_plane;
48 0 : m_chan_bin_length = n_channels_on_plane / m_num_chanbins;
49 : }
50 :
51 0 : TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TAM:BSMW] 1st Chan = " << m_first_channel << ", last Chan = " << m_last_channel << std::endl
52 0 : << "Number of channel bins = " << m_num_chanbins << ", and channel bin length = " << m_chan_bin_length;
53 0 : return;
54 : }
55 :
56 : // If the difference between the current TP's start time and the start of the window
57 : // is less than the specified window size, add the TP to the window.
58 0 : if((input_tp.time_start - m_current_window.time_start) < m_window_length){
59 0 : TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TAM:BSMW] Window not yet complete, adding the input_tp to the window.";
60 0 : m_current_window.add(input_tp);
61 : }
62 : // If the addition of the current TP to the window would make it longer
63 : // than the specified window length, don't add it
64 : // Instead go through a series of filters and eventually a XGBoost model to determine whether to create a TA
65 0 : else if (
66 0 : (m_current_window.time_start - m_last_pred_time) > m_bin_length && // check enough time has passed since last window
67 0 : m_current_window.tp_list.size() > 20 && // need enough TPs in window to bother
68 0 : m_current_window.adc_integral > m_adc_threshold && // set a low minimum threshold for the ADC integral sum
69 0 : (m_current_window.mean_adc_peak() / m_current_window.mean_tot()) > m_ratio_threshold && // mean peak / tot cut
70 0 : compute_treelite_classification() // XGBoost classifier
71 : )
72 : {
73 0 : TLOG_DEBUG(TLVL_DEBUG_LOW) << "[TAM:BSMW] ADC integral in window is greater than specified threshold.";
74 0 : output_ta.push_back(construct_ta());
75 0 : TLOG_DEBUG(TLVL_DEBUG_HIGH) << "[TAM:BSMW] Resetting window with input_tp.";
76 0 : m_current_window.reset(input_tp);
77 : }
78 : // If it is not, move the window along.
79 : else{
80 0 : TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TAM:BSMW] Window is at required length but adc threshold not met, shifting window along.";
81 0 : m_current_window.move(input_tp, m_window_length);
82 : }
83 :
84 0 : TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TAM:BSMW] " << m_current_window;
85 :
86 0 : m_primitive_count++;
87 :
88 0 : return;
89 :
90 : }
91 :
92 : void
93 0 : TAMakerProtoDUNEBSMWindowAlgorithm::configure(const nlohmann::json &config)
94 : {
95 0 : if (config.is_object()){
96 0 : if (config.contains("channel_map_name")) m_channel_map_name = config["channel_map_name"];
97 0 : if (config.contains("num_time_bins")) m_num_timebins = config["num_time_bins"];
98 0 : if (config.contains("adc_threshold")) m_adc_threshold = config["adc_threshold"];
99 0 : if (config.contains("ratio_threshold")) {
100 0 : m_ratio_threshold = config["ratio_threshold"];
101 0 : m_ratio_threshold *= 0.01;
102 : }
103 0 : if (config.contains("window_length")) {
104 0 : m_window_length = config["window_length"];
105 0 : m_bin_length = static_cast<timestamp_t>(m_window_length / m_num_timebins);
106 : }
107 0 : if (config.contains("bdt_threshold")) {
108 0 : uint64_t int_bdt_threshold = config["bdt_threshold"];
109 0 : if (int_bdt_threshold <= 100) m_bdt_threshold = static_cast<float>(int_bdt_threshold * 0.01);
110 0 : else if (int_bdt_threshold <= 1000) m_bdt_threshold = static_cast<float>(int_bdt_threshold * 0.001);
111 0 : else if (int_bdt_threshold <= 10000) m_bdt_threshold = static_cast<float>(int_bdt_threshold * 0.0001);
112 0 : else m_bdt_threshold = static_cast<float>(int_bdt_threshold * 0.01);
113 : }
114 : }
115 : else{
116 0 : TLOG_DEBUG(TLVL_IMPORTANT) << "[TAM:BSMW] The DEFAULT values of window_length and adc_threshold are being used.";
117 : }
118 :
119 0 : TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TAM:BSMW] Bin length is " << m_bin_length << " for a window of " << m_num_timebins <<
120 0 : " bins. ADC threshold across window set to " << m_adc_threshold;
121 :
122 0 : channelMap = dunedaq::detchannelmaps::make_tpc_map(m_channel_map_name);
123 :
124 : // If we are in PD-VD, set boolean to true to enable effective channel mapping
125 0 : if (m_channel_map_name == "PD2VDTPCChannelMap" || m_channel_map_name == "PD2VDBottomTPCChannelMap" ||
126 0 : m_channel_map_name == "PD2VDTopTPCChannelMap") {
127 0 : m_pdvd_map = true;
128 : } else { // else we are in PD-HD and we use true channel mapping
129 0 : m_pdvd_map = false;
130 : }
131 :
132 0 : m_compiled_model_interface = std::make_unique<CompiledModelInterface>(nbatch);
133 :
134 0 : const size_t num_feature = m_compiled_model_interface->GetNumFeatures();
135 :
136 0 : flat_batched_inputs.resize(num_feature);
137 :
138 0 : m_num_chanbins = num_feature / m_num_timebins;
139 :
140 0 : flat_batched_Entries.clear();
141 0 : for (size_t i = 0; i < num_feature; ++i) {
142 0 : union Entry zero;
143 0 : zero.fvalue = 0.0;
144 0 : flat_batched_Entries.emplace_back(zero);
145 : }
146 0 : }
147 :
148 0 : TAMakerProtoDUNEBSMWindowAlgorithm::~TAMakerProtoDUNEBSMWindowAlgorithm() {
149 : // Nothing to clean up
150 0 : }
151 :
152 : TriggerActivity
153 0 : TAMakerProtoDUNEBSMWindowAlgorithm::construct_ta() const
154 : {
155 0 : TLOG_DEBUG(TLVL_DEBUG_LOW) << "[TAM:BSMW] I am constructing a trigger activity!";
156 :
157 0 : TriggerPrimitive latest_tp_in_window = m_current_window.tp_list.back();
158 : // The time_peak, time_activity, channel_* and adc_peak fields of this TA are irrelevent
159 : // for the purpose of this trigger alg.
160 0 : TriggerActivity ta;
161 0 : ta.time_start = m_current_window.time_start;
162 0 : ta.time_end = latest_tp_in_window.time_start + latest_tp_in_window.samples_over_threshold * 32;
163 0 : ta.time_peak = latest_tp_in_window.samples_to_peak * 32 + latest_tp_in_window.time_start;
164 0 : ta.time_activity = ta.time_peak;
165 0 : ta.channel_start = latest_tp_in_window.channel;
166 0 : ta.channel_end = latest_tp_in_window.channel;
167 0 : ta.channel_peak = latest_tp_in_window.channel;
168 0 : ta.adc_integral = m_current_window.adc_integral;
169 0 : ta.adc_peak = latest_tp_in_window.adc_peak;
170 0 : ta.detid = latest_tp_in_window.detid;
171 0 : ta.type = TriggerActivity::Type::kTPC;
172 0 : ta.algorithm = TriggerActivity::Algorithm::kUnknown;
173 0 : ta.inputs = m_current_window.tp_list;
174 0 : return ta;
175 0 : }
176 :
177 0 : bool TAMakerProtoDUNEBSMWindowAlgorithm::compute_treelite_classification() {
178 :
179 0 : m_last_pred_time = m_current_window.time_start;
180 :
181 0 : m_current_window.bin_window(
182 0 : flat_batched_inputs, m_bin_length,
183 : m_chan_bin_length, m_num_timebins,
184 : m_num_chanbins, m_first_channel,
185 0 : m_pdvd_eff_channel_mapper, m_pdvd_map
186 : );
187 :
188 0 : m_current_window.fill_entry_window(flat_batched_Entries, flat_batched_inputs);
189 :
190 0 : std::vector<float> result(nbatch, 0.0f);
191 :
192 0 : m_compiled_model_interface->Predict(flat_batched_Entries.data(), result.data());
193 :
194 0 : return m_compiled_model_interface->Classify(result.data(), m_bdt_threshold);
195 :
196 0 : }
197 :
198 : // Register algo in TA Factory
199 12 : REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerProtoDUNEBSMWindowAlgorithm)
|