LDMX Software
tracking::reco::SiStripWaveformBuilder Class Reference

Assemble per-trigger pedestal-subtracted hits into full per-channel waveforms. More...

#include <SiStripWaveformBuilder.h>

Public Member Functions

 SiStripWaveformBuilder (const std::string &name, framework::Process &process)
 
void configure (framework::config::Parameters &ps) override
 Callback for the EventProcessor to configure itself from the given set of parameters.
 
void produce (framework::Event &event) override
 Process the event and put new data products into it.
 
void onProcessEnd () override
 Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.
 
- Public Member Functions inherited from framework::Producer
 Producer (const std::string &name, Process &process)
 Class constructor.
 
virtual void process (Event &event) final
 Processing an event for a Producer is calling produce.
 
- Public Member Functions inherited from framework::EventProcessor
 DECLARE_FACTORY (EventProcessor, EventProcessor *, const std::string &, Process &)
 declare that we have a factory for this class
 
 EventProcessor (const std::string &name, Process &process)
 Class constructor.
 
virtual ~EventProcessor ()=default
 Class destructor.
 
virtual void beforeNewRun (ldmx::RunHeader &run_header)
 Callback for Producers to add parameters to the run header before conditions are initialized.
 
virtual void onNewRun (const ldmx::RunHeader &run_header)
 Callback for the EventProcessor to take any necessary action when the run being processed changes.
 
virtual void onFileOpen (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a new event input ROOT file is opened.
 
virtual void onFileClose (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a event input ROOT file is closed.
 
virtual void onProcessStart ()
 Callback for the EventProcessor to take any necessary action when the processing of events starts, such as creating histograms.
 
template<class T >
const T & getCondition (const std::string &condition_name)
 Access a conditions object for the current event.
 
TDirectory * getHistoDirectory ()
 Access/create a directory in the histogram file for this event processor to create histograms and analysis tuples.
 
void setStorageHint (framework::StorageControl::Hint hint)
 Mark the current event as having the given storage control hint from this module_.
 
void setStorageHint (framework::StorageControl::Hint hint, const std::string &purposeString)
 Mark the current event as having the given storage control hint from this module and the given purpose string.
 
int getLogFrequency () const
 Get the current logging frequency from the process.
 
int getRunNumber () const
 Get the run number from the process.
 
std::string getName () const
 Get the processor name.
 
void createHistograms (const std::vector< framework::config::Parameters > &histos)
 Internal function which is used to create histograms passed from the python configuration @parma histos vector of Parameters that configure histograms to create.
 

Private Attributes

std::string input_collection_ {"TrackerHits"}
 
std::string input_pass_name_ {""}
 
std::string output_collection_ {"TrackerWaveforms"}
 
double high_threshold_
 per-sample significance for high-threshold cut
 
int min_high_samples_ {4}
 min samples exceeding high_threshold
 
double low_threshold_
 per-sample significance for consecutive-streak cut
 
int min_consecutive_low_
 min consecutive samples exceeding low_threshold
 
int n_triggers_ {10}
 expected APV triggers per RoR
 
std::unique_ptr< tracking::digitization::PulseShapepulse_shape_
 Pulse shape used for the per-waveform fit test (built lazily in produce).
 
long n_fit_attempted_ {0}
 waveforms passed to the fitter
 
long n_fit_failed_ {0}
 fits that did not converge
 

Additional Inherited Members

- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 
- Protected Attributes inherited from framework::EventProcessor
HistogramPool histograms_
 helper object for making and filling histograms
 
NtupleManagerntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Assemble per-trigger pedestal-subtracted hits into full per-channel waveforms.

Each RoR issues n_triggers APV triggers, each producing a 3-sample (pedestal-subtracted) RawSiStripHit per channel. This producer groups all trigger hits for the same (feb, hybrid, pchannel), sorts by apv_trigger, and concatenates their samples into a SiStripWaveform with n_triggers*3 samples ordered as [s0_t0, s1_t0, s2_t0, s0_t1, ...].

The per-channel noise used for the significance cuts is obtained from the TrackerPedestals conditions object (a service); the physical strip number (pchannel) is derived from the hit's apv_id/channel via channelmap.

Two-stage threshold applied before writing:

  1. High-threshold count: at least min_high_samples samples with ADC/noise > high_threshold (default: 4 samples > 5σ).
  2. Consecutive low-threshold streak: at least min_consecutive_low consecutive samples with ADC/noise > low_threshold (default: 5 consecutive samples > 3σ). Both conditions must be satisfied; this strongly suppresses noise while retaining real APV25 signal pulses.

Definition at line 36 of file SiStripWaveformBuilder.h.

Constructor & Destructor Documentation

◆ SiStripWaveformBuilder()

tracking::reco::SiStripWaveformBuilder::SiStripWaveformBuilder ( const std::string & name,
framework::Process & process )
inline

Definition at line 38 of file SiStripWaveformBuilder.h.

Base class for a module which produces a data product.
virtual void process(Event &event) final
Processing an event for a Producer is calling produce.

Member Function Documentation

◆ configure()

void tracking::reco::SiStripWaveformBuilder::configure ( framework::config::Parameters & parameters)
overridevirtual

Callback for the EventProcessor to configure itself from the given set of parameters.

The parameters a processor has access to are the member variables of the python class in the sequence that has class_name equal to the EventProcessor class name.

For an example, look at MyProcessor.

Parameters
parametersParameters for configuration.

Reimplemented from framework::EventProcessor.

Definition at line 14 of file SiStripWaveformBuilder.cxx.

14 {
15 input_collection_ =
16 ps.get<std::string>("input_collection", input_collection_);
17 input_pass_name_ = ps.get<std::string>("input_pass_name", input_pass_name_);
18 output_collection_ =
19 ps.get<std::string>("output_collection", output_collection_);
20 high_threshold_ = ps.get<double>("high_threshold", high_threshold_);
21 min_high_samples_ = ps.get<int>("min_high_samples", min_high_samples_);
22 low_threshold_ = ps.get<double>("low_threshold", low_threshold_);
24 ps.get<int>("min_consecutive_low", min_consecutive_low_);
25 n_triggers_ = ps.get<int>("n_triggers", n_triggers_);
26}
double high_threshold_
per-sample significance for high-threshold cut
int min_consecutive_low_
min consecutive samples exceeding low_threshold
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

References framework::config::Parameters::get(), high_threshold_, low_threshold_, min_consecutive_low_, min_high_samples_, and n_triggers_.

◆ onProcessEnd()

void tracking::reco::SiStripWaveformBuilder::onProcessEnd ( )
overridevirtual

Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.

Reimplemented from framework::EventProcessor.

Definition at line 164 of file SiStripWaveformBuilder.cxx.

164 {
165 const long n_ok = n_fit_attempted_ - n_fit_failed_;
166 const double fail_pct =
168 ? 100.0 * static_cast<double>(n_fit_failed_) / n_fit_attempted_
169 : 0.0;
170 ldmx_log(info) << "Fit summary: " << n_fit_attempted_ << " attempted, "
171 << n_ok << " converged, " << n_fit_failed_ << " failed ("
172 << fail_pct << "%)";
173}
long n_fit_attempted_
waveforms passed to the fitter
long n_fit_failed_
fits that did not converge

References n_fit_attempted_, and n_fit_failed_.

◆ produce()

void tracking::reco::SiStripWaveformBuilder::produce ( framework::Event & event)
overridevirtual

Process the event and put new data products into it.

Parameters
eventThe Event to process.

Implements framework::Producer.

Definition at line 28 of file SiStripWaveformBuilder.cxx.

28 {
29 const auto& peds =
31
32 const auto& hits = event.getCollection<ldmx::RawSiStripHit>(input_collection_,
33 input_pass_name_);
34
35 // Build the pulse shape once (reused for every channel fit this job).
36 if (!pulse_shape_) {
38 std::string(tracking::digitization::PULSE_SHAPE_NAME),
39 tracking::digitization::PEAKING_TIME_NS,
40 tracking::digitization::SECOND_TIME_CONST_NS);
41 }
42
43 // Key: encodes (feb, hybrid, pchannel) uniquely.
44 // Value: vector of (apv_trigger, samples) pairs.
45 struct TriggerSamples {
46 uint16_t apv_trigger_;
47 std::vector<short> samples_;
48 };
49 struct ChannelInfo {
50 float noise_{0};
51 uint8_t hybrid_id_{0};
52 uint8_t feb_id_{0};
53 std::vector<TriggerSamples> triggers_;
54 };
55
56 // Use a map keyed by (feb, hybrid, pchannel) for grouping.
57 std::map<uint32_t, ChannelInfo> channel_map;
58
59 for (const auto& hit : hits) {
60 const float noise = peds.noise(hit.getFebId(), hit.getHybridId(),
61 hit.getApvId(), hit.getChannel());
62 if (noise <= 0) continue;
63
64 const int16_t pchannel =
65 channelmap::pchannel(hit.getApvId(), hit.getChannel());
66 uint32_t key =
67 channelmap::groupKey(hit.getFebId(), hit.getHybridId(), pchannel);
68
69 auto& ch = channel_map[key];
70 ch.noise_ = noise;
71 ch.hybrid_id_ = hit.getHybridId();
72 ch.feb_id_ = hit.getFebId();
73 ch.triggers_.push_back({hit.getApvTrigger(), hit.getSamples()});
74 }
75
76 std::vector<ldmx::SiStripWaveform> waveforms;
77
78 for (auto& [key, ch] : channel_map) {
79 // Sort triggers by apv_trigger index.
80 std::sort(ch.triggers_.begin(), ch.triggers_.end(),
81 [](const TriggerSamples& a, const TriggerSamples& b) {
82 return a.apv_trigger_ < b.apv_trigger_;
83 });
84
85 // Assemble full waveform: [s0_t0, s1_t0, s2_t0, s0_t1, ...].
86 std::vector<short> samples;
87 samples.reserve(ch.triggers_.size() *
89 for (const auto& trig : ch.triggers_) {
90 for (short s : trig.samples_) samples.push_back(s);
91 }
92
93 if (samples.empty()) continue;
94
95 // Condition 1: at least min_high_samples_ samples exceed high_threshold_.
96 int n_high = 0;
97 for (short s : samples)
98 if (static_cast<float>(s) / ch.noise_ > high_threshold_) ++n_high;
99 if (n_high < min_high_samples_) continue;
100
101 // Condition 2: at least min_consecutive_low_ consecutive samples exceed
102 // low_threshold_.
103 int max_streak = 0, cur_streak = 0;
104 for (short s : samples) {
105 if (static_cast<float>(s) / ch.noise_ > low_threshold_) {
106 max_streak = std::max(max_streak, ++cur_streak);
107 } else {
108 cur_streak = 0;
109 }
110 }
111 if (max_streak < min_consecutive_low_) continue;
112
114 uint8_t n_trig = static_cast<uint8_t>(
115 std::min(static_cast<int>(ch.triggers_.size()), 255));
116
117 // --- TEST: fit a CR-RC pulse shape to the full assembled waveform. ---
118 // Samples are pedestal-subtracted (ped = 0) and lie on a uniform 25 ns
119 // grid, so the scan range is sized to the waveform: T may peak anywhere
120 // from before sample 0 to the last sample.
121 const int n_samples = static_cast<int>(samples.size());
122 const double t_scan_max =
123 n_samples * tracking::digitization::SAMPLING_INTERVAL_NS;
126 /*t0_offset_ns=*/0.0,
127 tracking::digitization::SAMPLING_INTERVAL_NS,
128 /*pedestal_adc=*/0.0,
129 /*noise_sigma_adc=*/ch.noise_,
130 /*t_scan_min_ns=*/-50.0, t_scan_max, /*t_scan_step_ns=*/1.0);
131 const auto fit = fitter.fit(samples);
133 if (!fit.converged) ++n_fit_failed_;
134
135 ldmx_log(trace) << "fit feb=" << static_cast<int>(ch.feb_id_)
136 << " hyb=" << static_cast<int>(ch.hybrid_id_)
137 << " pch=" << pchannel << " nsamp=" << n_samples
138 << " noise=" << ch.noise_
139 << " -> converged=" << (fit.converged ? "yes" : "no")
140 << " amp=" << fit.amplitude << " t0=" << fit.t0 << "ns"
141 << " chi2/ndf=" << fit.chi2 << "/" << fit.ndf << " ("
142 << (fit.ndf > 0 ? fit.chi2 / fit.ndf : 0.0) << ")";
143
144 waveforms.emplace_back(std::move(samples), pchannel, ch.hybrid_id_,
145 ch.feb_id_, n_trig);
146 waveforms.back().setFitResult(
147 static_cast<float>(fit.amplitude), static_cast<float>(fit.t0),
148 static_cast<float>(fit.chi2), fit.ndf, fit.converged);
149 }
150
151 ldmx_log(debug) << "Built " << waveforms.size()
152 << " waveforms (>=" << min_high_samples_ << " samples @"
153 << high_threshold_ << "s, streak>=" << min_consecutive_low_
154 << " @" << low_threshold_ << "s) from " << hits.size()
155 << " hits";
156
157 for (const auto& wf : waveforms) {
158 ldmx_log(trace) << wf;
159 }
160
161 event.add(output_collection_, waveforms);
162}
const T & getCondition(const std::string &condition_name)
Access a conditions object for the current event.
Implementation of a raw digitized hit from a silicon strip detector.
static std::unique_ptr< PulseShape > make(const std::string &name, double tp, double tp2=0.0)
Factory: construct a pulse shape by name.
Fits a pulse shape to the ADC samples of a single silicon-strip readout channel to extract hit amplit...
std::unique_ptr< tracking::digitization::PulseShape > pulse_shape_
Pulse shape used for the per-waveform fit test (built lazily in produce).
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,...

References tracking::reco::TrackerPedestals::CONDITIONS_NAME, tracking::digitization::StripPulseFitter::fit(), framework::EventProcessor::getCondition(), tracking::reco::channelmap::groupKey(), high_threshold_, tracking::reco::channelmap::K_SAMPLES_PER_APV_TRIGGER, low_threshold_, tracking::digitization::PulseShape::make(), min_consecutive_low_, min_high_samples_, n_fit_attempted_, n_fit_failed_, tracking::reco::channelmap::pchannel(), tracking::reco::channelmap::pchannelFromGroupKey(), and pulse_shape_.

Member Data Documentation

◆ high_threshold_

double tracking::reco::SiStripWaveformBuilder::high_threshold_
private
Initial value:
{
5.0}

per-sample significance for high-threshold cut

Definition at line 49 of file SiStripWaveformBuilder.h.

49 {
50 5.0};

Referenced by configure(), and produce().

◆ input_collection_

std::string tracking::reco::SiStripWaveformBuilder::input_collection_ {"TrackerHits"}
private

Definition at line 46 of file SiStripWaveformBuilder.h.

46{"TrackerHits"};

◆ input_pass_name_

std::string tracking::reco::SiStripWaveformBuilder::input_pass_name_ {""}
private

Definition at line 47 of file SiStripWaveformBuilder.h.

47{""};

◆ low_threshold_

double tracking::reco::SiStripWaveformBuilder::low_threshold_
private
Initial value:
{
3.0}

per-sample significance for consecutive-streak cut

Definition at line 52 of file SiStripWaveformBuilder.h.

52 {
53 3.0};

Referenced by configure(), and produce().

◆ min_consecutive_low_

int tracking::reco::SiStripWaveformBuilder::min_consecutive_low_
private
Initial value:
{
5}

min consecutive samples exceeding low_threshold

Definition at line 54 of file SiStripWaveformBuilder.h.

54 {
55 5};

Referenced by configure(), and produce().

◆ min_high_samples_

int tracking::reco::SiStripWaveformBuilder::min_high_samples_ {4}
private

min samples exceeding high_threshold

Definition at line 51 of file SiStripWaveformBuilder.h.

51{4};

Referenced by configure(), and produce().

◆ n_fit_attempted_

long tracking::reco::SiStripWaveformBuilder::n_fit_attempted_ {0}
private

waveforms passed to the fitter

Definition at line 63 of file SiStripWaveformBuilder.h.

63{0};

Referenced by onProcessEnd(), and produce().

◆ n_fit_failed_

long tracking::reco::SiStripWaveformBuilder::n_fit_failed_ {0}
private

fits that did not converge

Definition at line 64 of file SiStripWaveformBuilder.h.

64{0};

Referenced by onProcessEnd(), and produce().

◆ n_triggers_

int tracking::reco::SiStripWaveformBuilder::n_triggers_ {10}
private

expected APV triggers per RoR

Definition at line 56 of file SiStripWaveformBuilder.h.

56{10};

Referenced by configure().

◆ output_collection_

std::string tracking::reco::SiStripWaveformBuilder::output_collection_ {"TrackerWaveforms"}
private

Definition at line 48 of file SiStripWaveformBuilder.h.

48{"TrackerWaveforms"};

◆ pulse_shape_

std::unique_ptr<tracking::digitization::PulseShape> tracking::reco::SiStripWaveformBuilder::pulse_shape_
private

Pulse shape used for the per-waveform fit test (built lazily in produce).

Definition at line 59 of file SiStripWaveformBuilder.h.

Referenced by produce().


The documentation for this class was generated from the following files: