LCOV - code coverage report
Current view: top level - triggeralgs/src - TAMakerChannelAdjacencyAlgorithm.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.9 % 115 1
Test Date: 2025-12-21 13:07:08 Functions: 10.0 % 10 1

            Line data    Source code
       1              : /**
       2              :  * @file TAMakerChannelAdjacencyAlgorithm.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/ChannelAdjacency/TAMakerChannelAdjacencyAlgorithm.hpp"
      10              : #include "TRACE/trace.h"
      11              : #include "triggeralgs/Logging.hpp"
      12              : #define TRACE_NAME "TAMakerChannelAdjacencyAlgorithm"
      13              : #include <math.h>
      14              : #include <vector>
      15              : 
      16              : using namespace triggeralgs;
      17              : 
      18              : using Logging::TLVL_DEBUG_LOW;
      19              : 
      20              : void
      21            0 : TAMakerChannelAdjacencyAlgorithm::process(const TriggerPrimitive& input_tp,
      22              :                                               std::vector<TriggerActivity>& output_ta)
      23              : {
      24              : 
      25              :   // Add useful info about recived TPs here for FW and SW TPG guys.
      26            0 :   if (m_print_tp_info) {
      27            0 :     TLOG_DEBUG(TLVL_DEBUG_LOW) << " ########## m_current_window is reset ##########\n"
      28            0 :                                << " TP Start Time: " << input_tp.time_start << ", TP ADC Sum: " << input_tp.adc_integral
      29            0 :                                << ", TP SOT: " << input_tp.samples_over_threshold << ", TP ADC Peak: " << input_tp.adc_peak
      30            0 :                                << ", TP Offline Channel ID: " << input_tp.channel << "\n";
      31              :   }
      32              : 
      33              :   // 0) FIRST TP =====================================================================
      34              :   // The first time process() is called, reset the window object.
      35            0 :   if (m_current_window.is_empty()) {
      36            0 :     m_current_window.reset(input_tp);
      37            0 :     return;
      38              :   }
      39              : 
      40              :   // If the difference between the current TP's start time and the start of the window
      41              :   // is less than the specified window size, add the TP to the window.
      42            0 :   bool adj_pass = 0;      // sets to true when adjacency logic is satisfied
      43            0 :   bool window_filled = 1; // sets to true when window is ready to test the adjacency logic
      44            0 :   if ((input_tp.time_start - m_current_window.time_start) < m_window_length) {
      45            0 :     m_current_window.add(input_tp);
      46            0 :     window_filled = 0;
      47            0 :     TLOG_DEBUG(TLVL_DEBUG_LOW) << "m_current_window.time_start " << m_current_window.time_start << "\n";
      48              :   }
      49              : 
      50              :   else {
      51            0 :     TPWindow win_adj_max;
      52              : 
      53            0 :     bool ta_found = 1;
      54            0 :     while (ta_found) {
      55              : 
      56              :       // make m_current_window_tmp a copy of m_current_window and clear m_current_window
      57            0 :       TPWindow m_current_window_tmp = m_current_window;
      58            0 :       m_current_window.clear();
      59              : 
      60              :       // make m_current_window a new window of non-overlapping tps (of m_current_window_tmp and win_adj_max)
      61            0 :       for (auto tp : m_current_window_tmp.inputs) {
      62            0 :         bool new_tp = 1;
      63            0 :         for (auto tp_sel : win_adj_max.inputs) {
      64            0 :           if (tp.channel == tp_sel.channel) {
      65              :             new_tp = 0;
      66              :             break;
      67              :           }
      68              :         }
      69            0 :         if (new_tp)
      70            0 :           m_current_window.add(tp);
      71              :       }
      72              : 
      73              :       // check adjacency -> win_adj_max now contains only those tps that make the track
      74            0 :       win_adj_max = check_adjacency();
      75            0 :       if (win_adj_max.inputs.size() > 0) {
      76              : 
      77            0 :         adj_pass = 1;
      78            0 :         ta_found = 1;
      79            0 :         output_ta.push_back(construct_ta(win_adj_max));
      80              :       } else
      81              :         ta_found = 0;
      82            0 :     }
      83            0 :     if (adj_pass)
      84            0 :       m_current_window.reset(input_tp);
      85            0 :   }
      86              : 
      87              :   // if adjacency logic is not true, slide the window along using the current TP.
      88            0 :   if (window_filled && !adj_pass) {
      89            0 :     m_current_window.move(input_tp, m_window_length);
      90              :   }
      91              : 
      92              :   return;
      93              : }
      94              : 
      95              : void
      96            0 : TAMakerChannelAdjacencyAlgorithm::configure(const nlohmann::json& config)
      97              : {
      98            0 :   TriggerActivityMaker::configure(config);
      99            0 :   if (config.is_object()) {
     100            0 :     if (config.contains("window_length"))
     101            0 :       m_window_length = config["window_length"];
     102            0 :     if (config.contains("adjacency_tolerance"))
     103            0 :       m_adj_tolerance = config["adjacency_tolerance"];
     104            0 :     if (config.contains("adjacency_threshold"))
     105            0 :       m_adjacency_threshold = config["adjacency_threshold"];
     106            0 :     if (config.contains("print_tp_info"))
     107            0 :       m_print_tp_info = config["print_tp_info"];
     108              :   }
     109            0 : }
     110              : 
     111              : TriggerActivity
     112            0 : TAMakerChannelAdjacencyAlgorithm::construct_ta(TPWindow win_adj_max) const
     113              : {
     114              : 
     115            0 :   TriggerActivity ta;
     116              : 
     117            0 :   TriggerPrimitive last_tp = win_adj_max.inputs.back();
     118              : 
     119            0 :   ta.time_start = last_tp.time_start;
     120            0 :   ta.time_end = last_tp.time_start;
     121            0 :   ta.time_peak = last_tp.samples_to_peak * 32 + last_tp.time_start;  // FIXME: Replace STP to `time_peak` conversion.
     122            0 :   ta.time_activity = ta.time_peak;
     123            0 :   ta.channel_start = last_tp.channel;
     124            0 :   ta.channel_end = last_tp.channel;
     125            0 :   ta.channel_peak = last_tp.channel;
     126            0 :   ta.adc_integral = win_adj_max.adc_integral;
     127            0 :   ta.adc_peak = last_tp.adc_peak;
     128            0 :   ta.detid = last_tp.detid;
     129            0 :   ta.type = TriggerActivity::Type::kTPC;
     130            0 :   ta.algorithm = TriggerActivity::Algorithm::kChannelAdjacency;
     131            0 :   ta.inputs = win_adj_max.inputs;
     132              : 
     133            0 :   for (const auto& tp : ta.inputs) {
     134            0 :     ta.time_start = std::min(ta.time_start, tp.time_start);
     135            0 :     ta.time_end = std::max(ta.time_end, tp.time_start);
     136            0 :     ta.channel_start = std::min(ta.channel_start, channel_t(tp.channel));
     137            0 :     ta.channel_end = std::max(ta.channel_end, channel_t(tp.channel));
     138            0 :     if (tp.adc_peak > ta.adc_peak) {
     139            0 :       ta.time_peak = tp.samples_to_peak * 32 + tp.time_start;  // FIXME: Replace STP to `time_peak` conversion.
     140            0 :       ta.adc_peak = tp.adc_peak;
     141            0 :       ta.channel_peak = tp.channel;
     142              :     }
     143              :   }
     144              : 
     145            0 :   return ta;
     146            0 : }
     147              : 
     148              : // std::vector<TriggerPrimitive>
     149              : TPWindow
     150            0 : TAMakerChannelAdjacencyAlgorithm::check_adjacency()
     151              : {
     152              :   // This function deals with tp window (m_current_window), select adjacent tps (with a channel gap from 0 to 5; sum of
     153              :   // all gaps < m_adj_tolerance), checks if track length > m_adjacency_threshold: return the tp window (win_adj_max,
     154              :   // which is subset of the input tp window)
     155              : 
     156            0 :   unsigned int channel = 0;      // Current channel ID
     157            0 :   unsigned int next_channel = 0; // Next channel ID
     158            0 :   unsigned int next = 0;         // The next position in the hit channels vector
     159            0 :   unsigned int tol_count = 0;    // Tolerance count, should not pass adj_tolerance
     160              : 
     161              :   // Generate a channelID ordered list of hit channels for this window; second element of pair is tps
     162            0 :   std::vector<std::pair<int, TriggerPrimitive>> chanTPList;
     163            0 :   for (auto tp : m_current_window.inputs) {
     164            0 :     chanTPList.push_back(std::make_pair(channel_t(tp.channel), tp));
     165              :   }
     166            0 :   std::sort(chanTPList.begin(),
     167              :             chanTPList.end(),
     168            0 :             [](const std::pair<int, TriggerPrimitive>& a, const std::pair<int, TriggerPrimitive>& b) {
     169            0 :               return (a.first < b.first);
     170              :             });
     171              : 
     172              :   // ADAJACENCY LOGIC ====================================================================
     173              :   // =====================================================================================
     174              :   // Adjcancency Tolerance = Number of times prepared to skip missed hits before resetting
     175              :   // the adjacency count (win_adj). This accounts for things like dead channels / missed TPs.
     176              : 
     177              :   // add first tp, and then if tps are on next channels (check code below to understand the definition)
     178            0 :   TPWindow win_adj;
     179            0 :   TPWindow win_adj_max; // if track length > m_adjacency_threshold, set win_adj_max = win_adj; return win_adj_max;
     180              : 
     181            0 :   for (int i = 0; i < chanTPList.size(); ++i) {
     182              : 
     183            0 :     win_adj_max.clear();
     184              : 
     185            0 :     next = (i + 1) % chanTPList.size(); // Loops back when outside of channel list range
     186            0 :     channel = chanTPList.at(i).first;
     187            0 :     next_channel = chanTPList.at(next).first; // Next channel with a hit
     188              : 
     189              :     // End of vector condition.
     190            0 :     if (next == 0) {
     191            0 :       next_channel = channel - 1;
     192              :     }
     193              : 
     194              :     // Skip same channel hits.
     195            0 :     if (next_channel == channel)
     196            0 :       continue;
     197              : 
     198              :     // If win_adj size == zero, add current tp
     199            0 :     if (win_adj.inputs.size() == 0)
     200            0 :       win_adj.add(chanTPList[i].second);
     201              : 
     202              :     // If next hit is on next channel, increment the adjacency count
     203            0 :     if (next_channel - channel == 1) {
     204            0 :       win_adj.add(chanTPList[next].second);
     205              :     }
     206              : 
     207              :     // Allow a max gap of 5 channels (e.g., 45 and 50; 46, 47, 48, 49 are missing); increment the adjacency count
     208              :     // 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)
     209            0 :     else if (next_channel - channel > 0 && next_channel - channel <= 5 && tol_count < m_adj_tolerance) {
     210            0 :       win_adj.add(chanTPList[next].second);
     211            0 :       tol_count += next_channel - channel - 1;
     212              :     }
     213              : 
     214              :     // if track length > m_adjacency_threshold, set win_adj_max = win_adj;
     215            0 :     else if (win_adj.inputs.size() > m_adjacency_threshold) {
     216            0 :       win_adj_max = win_adj;
     217              :       break;
     218              :     }
     219              : 
     220              :     // If track length < m_adjacency_threshold, reset variables for next iteration.
     221              :     else {
     222            0 :       tol_count = 0;
     223            0 :       win_adj.clear();
     224              :     }
     225              :   }
     226              : 
     227            0 :   return win_adj_max;
     228            0 : }
     229              : 
     230              : // =====================================================================================
     231              : // Functions below this line are for debugging purposes.
     232              : // =====================================================================================
     233              : void
     234            0 : TAMakerChannelAdjacencyAlgorithm::add_window_to_record(TPWindow window)
     235              : {
     236            0 :   m_window_record.push_back(window);
     237            0 :   return;
     238              : }
     239              : 
     240              : // Register algo in TA Factory
     241           12 : REGISTER_TRIGGER_ACTIVITY_MAKER(TRACE_NAME, TAMakerChannelAdjacencyAlgorithm)
        

Generated by: LCOV version 2.0-1