LDMX Software
SiStripWaveformBuilder.cxx
1#include "Tracking/Reco/SiStripWaveformBuilder.h"
2
3#include <algorithm>
4#include <map>
5
6#include "Tracking/Event/RawSiStripHit.h"
7#include "Tracking/Event/SiStripWaveform.h"
8#include "Tracking/Reco/SiStripChannelMap.h"
9#include "Tracking/Reco/TrackerPedestals.h"
10
11namespace tracking::reco {
12
14 input_collection_ =
15 ps.get<std::string>("input_collection", input_collection_);
16 input_pass_name_ = ps.get<std::string>("input_pass_name", input_pass_name_);
17 output_collection_ =
18 ps.get<std::string>("output_collection", output_collection_);
19 high_threshold_ = ps.get<double>("high_threshold", high_threshold_);
20 min_high_samples_ = ps.get<int>("min_high_samples", min_high_samples_);
21 low_threshold_ = ps.get<double>("low_threshold", low_threshold_);
23 ps.get<int>("min_consecutive_low", min_consecutive_low_);
24 n_triggers_ = ps.get<int>("n_triggers", n_triggers_);
25}
26
28 const auto& peds =
30
31 const auto& hits = event.getCollection<ldmx::RawSiStripHit>(input_collection_,
32 input_pass_name_);
33
34 // Key: encodes (feb, hybrid, pchannel) uniquely.
35 // Value: vector of (apv_trigger, samples) pairs.
36 struct TriggerSamples {
37 uint16_t apv_trigger_;
38 std::vector<short> samples_;
39 };
40 struct ChannelInfo {
41 float noise_{0};
42 uint8_t hybrid_id_{0};
43 uint8_t feb_id_{0};
44 std::vector<TriggerSamples> triggers_;
45 };
46
47 // Use a map keyed by (feb, hybrid, pchannel) for grouping.
48 std::map<uint32_t, ChannelInfo> channel_map;
49
50 for (const auto& hit : hits) {
51 const float noise = peds.noise(hit.getFebId(), hit.getHybridId(),
52 hit.getApvId(), hit.getChannel());
53 if (noise <= 0) continue;
54
55 const int16_t pchannel =
56 channelmap::pchannel(hit.getApvId(), hit.getChannel());
57 uint32_t key =
58 channelmap::groupKey(hit.getFebId(), hit.getHybridId(), pchannel);
59
60 auto& ch = channel_map[key];
61 ch.noise_ = noise;
62 ch.hybrid_id_ = hit.getHybridId();
63 ch.feb_id_ = hit.getFebId();
64 ch.triggers_.push_back({hit.getApvTrigger(), hit.getSamples()});
65 }
66
67 std::vector<ldmx::SiStripWaveform> waveforms;
68
69 for (auto& [key, ch] : channel_map) {
70 // Sort triggers by apv_trigger index.
71 std::sort(ch.triggers_.begin(), ch.triggers_.end(),
72 [](const TriggerSamples& a, const TriggerSamples& b) {
73 return a.apv_trigger_ < b.apv_trigger_;
74 });
75
76 // Assemble full waveform: [s0_t0, s1_t0, s2_t0, s0_t1, ...].
77 std::vector<short> samples;
78 samples.reserve(ch.triggers_.size() *
80 for (const auto& trig : ch.triggers_) {
81 for (short s : trig.samples_) samples.push_back(s);
82 }
83
84 if (samples.empty()) continue;
85
86 // Condition 1: at least min_high_samples_ samples exceed high_threshold_.
87 int n_high = 0;
88 for (short s : samples)
89 if (static_cast<float>(s) / ch.noise_ > high_threshold_) ++n_high;
90 if (n_high < min_high_samples_) continue;
91
92 // Condition 2: at least min_consecutive_low_ consecutive samples exceed
93 // low_threshold_.
94 int max_streak = 0, cur_streak = 0;
95 for (short s : samples) {
96 if (static_cast<float>(s) / ch.noise_ > low_threshold_) {
97 max_streak = std::max(max_streak, ++cur_streak);
98 } else {
99 cur_streak = 0;
100 }
101 }
102 if (max_streak < min_consecutive_low_) continue;
103
104 int16_t pchannel = channelmap::pchannelFromGroupKey(key);
105 uint8_t n_trig = static_cast<uint8_t>(
106 std::min(static_cast<int>(ch.triggers_.size()), 255));
107
108 waveforms.emplace_back(std::move(samples), pchannel, ch.hybrid_id_,
109 ch.feb_id_, n_trig);
110 }
111
112 ldmx_log(debug) << "Built " << waveforms.size()
113 << " waveforms (>=" << min_high_samples_ << " samples @"
114 << high_threshold_ << "s, streak>=" << min_consecutive_low_
115 << " @" << low_threshold_ << "s) from " << hits.size()
116 << " hits";
117
118 for (const auto& wf : waveforms) {
119 ldmx_log(trace) << wf;
120 }
121
122 event.add(output_collection_, waveforms);
123}
124
125} // namespace tracking::reco
126
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
const T & getCondition(const std::string &condition_name)
Access a conditions object for the current event.
Implements an event buffer system for storing event data.
Definition Event.h:40
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:26
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
Implementation of a raw digitized hit from a silicon strip detector.
Assemble per-trigger pedestal-subtracted hits into full per-channel waveforms.
double high_threshold_
per-sample significance for high-threshold cut
int min_consecutive_low_
min consecutive samples exceeding low_threshold
void configure(framework::config::Parameters &ps) override
Callback for the EventProcessor to configure itself from the given set of parameters.
int n_triggers_
expected APV triggers per RoR
int min_high_samples_
min samples exceeding high_threshold
double low_threshold_
per-sample significance for consecutive-streak cut
void produce(framework::Event &event) override
Process the event and put new data products into it.
static const std::string CONDITIONS_NAME
Name of the conditions object (must match the python registration).
constexpr int K_SAMPLES_PER_APV_TRIGGER
Number of ADC samples the APV25 reads out per channel per trigger.
constexpr int16_t pchannelFromGroupKey(uint32_t key)
Extract the pchannel back out of a key produced by groupKey().
constexpr uint32_t groupKey(uint8_t feb, uint8_t hybrid, int16_t pchannel)
Pack (feb, hybrid, pchannel) into a single 32-bit waveform-grouping key.
constexpr int16_t pchannel(uint8_t apv_id, uint8_t channel)
Convert an (APV id, APV channel) pair into the physical strip number (pchannel) within a hybrid,...