DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
TAMakerHorizontalMuonAlgorithm.cpp
Go to the documentation of this file.
1
10#include "TRACE/trace.h"
11#define TRACE_NAME "TAMakerHorizontalMuonAlgorithm"
12#include <vector>
13#include <math.h>
14#include <vector>
15
16using namespace triggeralgs;
17
18using Logging::TLVL_DEBUG_ALL;
19using Logging::TLVL_DEBUG_MEDIUM;
20
21void
23 std::vector<TriggerActivity>& output_ta)
24{
25
26 uint16_t adjacency;
27
28 // Add useful info about recived TPs here for FW and SW TPG guys.
29 if (m_print_tp_info) {
30 TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TAM:HM] TP Start Time: " << input_tp.time_start
31 << ", TP ADC Sum: " << input_tp.adc_integral
32 << ", TP SOT: " << input_tp.samples_over_threshold << ", TP ADC Peak: " << input_tp.adc_peak
33 << ", TP Offline Channel ID: " << input_tp.channel;
34 TLOG_DEBUG(TLVL_DEBUG_ALL) << "[TAM:HM] Adjacency of current window is: " << check_adjacency();
35 }
36
37 // 0) FIRST TP =====================================================================
38 // The first time process() is called, reset the window object.
40 m_current_window.reset(input_tp);
41 return;
42 }
43
44 // If the difference between the current TP's start time and the start of the window
45 // is less than the specified window size, add the TP to the window.
47 m_current_window.add(input_tp);
48 }
49
50 // 1) ADC THRESHOLD EXCEEDED =======================================================
51 // If the addition of the current TP to the window would make it longer specified
52 // window length, don't add it but check whether the ADC integral if the existing
53 // window is above the configured threshold. If it is, and we are triggering on ADC,
54 // make a TA and start a fresh window with the current TP.
56
57 auto ta = construct_ta();
58
59 TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TA:HM]: Emitting ADC threshold trigger with " << m_current_window.adc_integral
60 << " window ADC integral. ta.time_start=" << ta.time_start
61 << " ta.time_end=" << ta.time_end;
62
63 output_ta.push_back(ta);
64 m_current_window.reset(input_tp);
65 }
66
67 // 2) MULTIPLICITY - N UNQIUE CHANNELS EXCEEDED =====================================
68 // If the addition of the current TP to the window would make it longer than the
69 // specified window length, don't add it but check whether the number of hit channels
70 // in the existing window is above the specified threshold. If it is, and we are triggering
71 // on channel multiplicity, make a TA and start a fresh window with the current TP.
73
74 TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TAM:HM] Emitting multiplicity trigger with "
75 << m_current_window.n_channels_hit() << " unique channels hit.";
76
77 output_ta.push_back(construct_ta());
78 m_current_window.reset(input_tp);
79 }
80
81 // 3) ADJACENCY THRESHOLD EXCEEDED ==================================================
82 // If the addition of the current TP to the window would make it longer than the
83 // specified window length, don't add it but check whether the adjacency of the
84 // current window exceeds the configured threshold. If it does, and we are triggering
85 // on adjacency, then create a TA and reset the window with the new/current TP.
86 else if ((adjacency = check_adjacency()) > m_adjacency_threshold && m_trigger_on_adjacency) {
87
88 //for (auto tp : m_current_window.inputs){ dump_tp(tp); }
89
90 // Check for a new maximum, display the largest seen adjacency in the log.
91 // uint16_t adjacency = check_adjacency();
92 if (adjacency > m_max_adjacency) {
93 m_max_adjacency = adjacency;
94 }
95 TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TAM:HM] Emitting track and multiplicity TA with adjacency "
96 << check_adjacency() << " and multiplicity " << m_current_window.n_channels_hit()
97 << ". The ADC integral of this TA is " << m_current_window.adc_integral
98 << " and the largest longest track seen so far is " << m_max_adjacency;
99
100 output_ta.push_back(construct_ta());
101 m_current_window.reset(input_tp);
102 }
103
104 // Temporary triggering logic for Adam's large SOT TPs. Trigger on very large SOT TPs.
106
107 // If the incoming TP has a large time over threshold, we might have a cluster of
108 // interesting physics activity surrounding it. Trigger on that.
109 TLOG_DEBUG(TLVL_DEBUG_MEDIUM) << "[TAM:HM] Emitting a TA due to a TP with a very large samples over threshold: "
110 << input_tp.samples_over_threshold << " ticks and offline channel: " << input_tp.channel
111 << ", where the ADC integral of that TP is " << input_tp.adc_integral;
112 output_ta.push_back(construct_ta());
113 m_current_window.reset(input_tp);
114 }
115
116 // 4) Otherwise, slide the window along using the current TP.
117 else {
119 }
120
121 return;
122}
123
124void
125TAMakerHorizontalMuonAlgorithm::configure(const nlohmann::json& config)
126{
128
129 if (config.is_object()) {
130 if (config.contains("trigger_on_adc"))
131 m_trigger_on_adc = config["trigger_on_adc"];
132 if (config.contains("trigger_on_n_channels"))
133 m_trigger_on_n_channels = config["trigger_on_n_channels"];
134 if (config.contains("adc_threshold"))
135 m_adc_threshold = config["adc_threshold"];
136 if (config.contains("n_channels_threshold"))
137 m_n_channels_threshold = config["n_channels_threshold"];
138 if (config.contains("window_length"))
139 m_window_length = config["window_length"];
140 if (config.contains("trigger_on_adjacency"))
141 m_trigger_on_adjacency = config["trigger_on_adjacency"];
142 if (config.contains("adjacency_tolerance"))
143 m_adj_tolerance = config["adjacency_tolerance"];
144 if (config.contains("adjacency_threshold"))
145 m_adjacency_threshold = config["adjacency_threshold"];
146 if (config.contains("print_tp_info"))
147 m_print_tp_info = config["print_tp_info"];
148 if (config.contains("trigger_on_sot"))
149 m_trigger_on_sot = config["trigger_on_sot"];
150 if (config.contains("sot_threshold"))
151 m_sot_threshold = config["sot_threshold"];
152 }
153
154}
155
158{
159
161
163
164 ta.time_start = last_tp.time_start;
165 ta.time_end = last_tp.time_start + last_tp.samples_over_threshold * 32; // FIXME: Replace the hard-coded SOT to TOT scaling.
166 ta.time_peak = last_tp.samples_to_peak * 32 + last_tp.time_start; // FIXME: Replace STP to `time_peak` conversion.
167 ta.time_activity = ta.time_peak;
168 ta.channel_start = last_tp.channel;
169 ta.channel_end = last_tp.channel;
170 ta.channel_peak = last_tp.channel;
172 ta.adc_peak = last_tp.adc_integral;
173 ta.detid = last_tp.detid;
177
178 for( const auto& tp : ta.inputs ) {
179 ta.time_start = std::min(ta.time_start, tp.time_start);
180 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.
181 ta.channel_start = std::min(ta.channel_start, channel_t(tp.channel));
182 ta.channel_end = std::max(ta.channel_end, channel_t(tp.channel));
183 if (tp.adc_peak > ta.adc_peak) {
184 ta.time_peak = tp.samples_to_peak * 32 + tp.time_start; // FIXME: Replace STP to `time_peak` conversion.
185 ta.adc_peak = tp.adc_peak;
186 ta.channel_peak = tp.channel;
187 }
188 }
189
190 return ta;
191}
192
193uint16_t
195{
196 // This function returns the adjacency value for the current window, where adjacency
197 // is defined as the maximum number of consecutive wires containing hits. It accepts
198 // a configurable tolerance paramter, which allows up to adj_tolerance missing hits
199 // on adjacent wires before restarting the adjacency count. The maximum gap is 4 which
200 // comes from tuning on December 2021 coldbox data, and June 2022 coldbox runs.
201
202 uint16_t adj = 1; // Initialise adjacency, 1 for the first wire.
203 uint16_t max = 0; // Maximum adjacency of window, which this function returns
204 unsigned int channel = 0; // Current channel ID
205 unsigned int next_channel = 0; // Next channel ID
206 unsigned int next = 0; // The next position in the hit channels vector
207 unsigned int tol_count = 0; // Tolerance count, should not pass adj_tolerance
208
209 // Generate a channelID ordered list of hit channels for this window
210 std::vector<int> chanList;
211 for (auto tp : m_current_window.inputs) {
212 chanList.push_back(channel_t(tp.channel));
213 }
214 std::sort(chanList.begin(), chanList.end());
215
216 // ADAJACENCY LOGIC ====================================================================
217 // =====================================================================================
218 // Adjcancency Tolerance = Number of times prepared to skip missed hits before resetting
219 // the adjacency count. This accounts for things like dead channels / missed TPs. The
220 // maximum gap is 4 which comes from tuning on December 2021 coldbox data, and June 2022
221 // coldbox runs.
222 for (int i = 0; i < chanList.size(); ++i) {
223
224 next = (i + 1) % chanList.size(); // Loops back when outside of channel list range
225 channel = chanList.at(i);
226 next_channel = chanList.at(next); // Next channel with a hit
227
228 // End of vector condition.
229 if (next_channel == 0) {
230 next_channel = channel - 1;
231 }
232
233 // Skip same channel hits.
234 if (next_channel == channel) {
235 continue;
236 }
237
238 // If next hit is on next channel, increment the adjacency count.
239 else if (next_channel == channel + 1) {
240 ++adj;
241 }
242
243 // If next channel is not on the next hit, but the 'second next', increase adjacency
244 // but also tally up with the tolerance counter.
245 else if (((next_channel == channel + 2) || (next_channel == channel + 3) || (next_channel == channel + 4) ||
246 (next_channel == channel + 5)) &&
247 (tol_count < m_adj_tolerance)) {
248 ++adj;
249 for (int i = 0; i < next_channel - channel; ++i) {
250 ++tol_count;
251 }
252 }
253
254 // If next hit isn't within reach, end the adjacency count and check for a new max.
255 // Reset variables for next iteration.
256 else {
257 if (adj > max) {
258 max = adj;
259 }
260 adj = 1;
261 tol_count = 0;
262 }
263 }
264
265 return max;
266}
267
268// =====================================================================================
269// Functions below this line are for debugging purposes.
270// =====================================================================================
271void
273{
274 m_window_record.push_back(window);
275 return;
276}
277
278// Function to dump the details of the TA window currently on record
279void
281{
282 std::ofstream outfile;
283 outfile.open("window_record_tam.csv", std::ios_base::app);
284
285 for (auto window : m_window_record) {
286 outfile << window.time_start << ",";
287 outfile << window.inputs.back().time_start << ",";
288 outfile << window.inputs.back().time_start - window.time_start << ",";
289 outfile << window.adc_integral << ",";
290 outfile << window.n_channels_hit() << ","; // Number of unique channels with hits
291 outfile << window.inputs.size() << ","; // Number of TPs in TPWindow
292 outfile << window.inputs.back().channel << ","; // Last TP Channel ID
293 outfile << window.inputs.front().channel << ","; // First TP Channel ID
294 outfile << check_adjacency() << ","; // New adjacency value for the window
295 outfile << check_sot() << std::endl; // Summed window SOT
296 }
297
298 outfile.close();
299 m_window_record.clear();
300
301 return;
302}
303
304// Function to add current TP details to a text file for testing and debugging.
305void
307{
308 std::ofstream outfile;
309 outfile.open("coldbox_tps.txt", std::ios_base::app);
310
311 // Output relevant TP information to file
312 outfile << input_tp.time_start << " ";
313 outfile << input_tp.samples_over_threshold << " "; // 50MHz ticks
314 outfile << input_tp.samples_to_peak << " ";
315 outfile << input_tp.channel << " "; // Offline channel ID
316 outfile << input_tp.adc_integral << " ";
317 outfile << input_tp.adc_peak << " ";
318 outfile << input_tp.detid << " "; // Det ID - Identifies detector element
319 outfile.close();
320
321 return;
322}
323
324int
326{
327 // Here, we just want to sum up all the sot values for each TP within window,
328 // and return this sot of the window.
329 int window_sot = 0;
330 for (auto tp : m_current_window.inputs) {
331 window_sot += tp.samples_over_threshold;
332 }
333
334 return window_sot;
335}
336
337// Register algo in TA Factory
#define REGISTER_TRIGGER_ACTIVITY_MAKER(tam_name, tam_class)
void process(const TriggerPrimitive &input_tp, std::vector< TriggerActivity > &output_ta)
TP processing function that creates & fills TAs.
void reset(TriggerPrimitive const &input_tp)
Definition TPWindow.cpp:79
void add(TriggerPrimitive const &input_tp)
Definition TPWindow.cpp:20
bool is_empty() const
Definition TPWindow.cpp:14
std::vector< TriggerPrimitive > inputs
Definition TPWindow.hpp:40
void move(TriggerPrimitive const &input_tp, timestamp_t const &window_length)
Definition TPWindow.cpp:45
timestamp_t time_start
Definition TPWindow.hpp:37
uint16_t n_channels_hit()
Definition TPWindow.cpp:39
virtual void configure(const nlohmann::json &config)
#define TLOG_DEBUG(lvl,...)
Definition Logging.hpp:112
dunedaq::trgdataformats::channel_t channel_t
Definition Types.hpp:20
#define TRACE_NAME
A single energy deposition on a TPC or PDS channel.
std::vector< TriggerPrimitive > inputs