1#include "Tracking/Reco/SiStripWaveformFitProcessor.h"
3#include "Framework/Exception/Exception.h"
4#include "Tracking/Digitization/SiStripConstants.h"
5#include "Tracking/Digitization/StripPulseFitter.h"
6#include "Tracking/Event/FittedSiStripHit.h"
7#include "Tracking/Event/SiStripWaveform.h"
8#include "Tracking/Reco/SiStripChannelMap.h"
9#include "Tracking/Reco/TrackerPedestals.h"
11namespace tracking::reco {
15 ps.
get<std::string>(
"input_collection", input_collection_);
16 input_pass_name_ = ps.
get<std::string>(
"input_pass_name", input_pass_name_);
18 ps.
get<std::string>(
"output_collection", output_collection_);
19 daq_map_file_ = ps.
get<std::string>(
"daq_map_file", daq_map_file_);
21 t_scan_min_ns_ = ps.
get<
double>(
"t_scan_min_ns", t_scan_min_ns_);
22 t_scan_max_ns_ = ps.
get<
double>(
"t_scan_max_ns", t_scan_max_ns_);
23 t_scan_step_ns_ = ps.
get<
double>(
"t_scan_step_ns", t_scan_step_ns_);
24 max_chi2_ndf_ = ps.
get<
double>(
"max_chi2_ndf", max_chi2_ndf_);
28 using namespace tracking::digitization;
30 if (daq_map_file_.empty()) {
31 EXCEPTION_RAISE(
"BadConfig",
32 "SiStripWaveformFitProcessor requires a daq_map_file.");
38 pulse_shape_ = PulseShape::make(std::string(PULSE_SHAPE_NAME),
39 PEAKING_TIME_NS, SECOND_TIME_CONST_NS);
41 ldmx_log(info) <<
"SiStripWaveformFitProcessor configured:"
42 <<
" daq_map='" << daq_map_file_ <<
"' (" << daq_map_.
size()
43 <<
" sensors)" <<
" shape=" << PULSE_SHAPE_NAME
44 <<
" tp=" << PEAKING_TIME_NS <<
" ns" <<
" T scan ["
45 << t_scan_min_ns_ <<
", "
46 << (t_scan_max_ns_ > 0.0 ? std::to_string(t_scan_max_ns_)
47 : std::string(
"auto"))
48 <<
"] ns" <<
" step=" << t_scan_step_ns_ <<
" ns";
52 using namespace tracking::digitization;
58 input_collection_, input_pass_name_);
60 std::vector<ldmx::FittedSiStripHit> hits;
61 hits.reserve(waveforms.size());
63 for (
const auto& wf : waveforms) {
70 const uint8_t feb = wf.getFebId();
71 const uint8_t hybrid = wf.getHybridId();
73 if (!daq_map_.
has(feb, hybrid)) {
76 static_cast<uint16_t
>((
static_cast<uint16_t
>(feb) << 8) | hybrid);
78 ldmx_log(warn) <<
"No DAQ-map entry for feb=" <<
static_cast<int>(feb)
79 <<
" hybrid=" <<
static_cast<int>(hybrid)
80 <<
" -- dropping its waveforms (reported once)";
85 const auto& sensor = daq_map_.
at(feb, hybrid);
86 const int16_t pchannel = wf.getPchannel();
88 pchannel, sensor.n_strips_, sensor.first_strip_, sensor.reversed_);
92 if (strip_id < sensor.first_strip_ ||
93 strip_id >= sensor.first_strip_ + sensor.n_strips_) {
102 uint8_t apv_id, channel;
104 const float noise = peds.noise(feb, hybrid, apv_id, channel);
106 const auto& samples = wf.getSamples();
107 const int n_samples =
static_cast<int>(samples.size());
110 const double t_scan_max = (t_scan_max_ns_ > 0.0)
112 : n_samples * SAMPLING_INTERVAL_NS;
115 0.0, SAMPLING_INTERVAL_NS,
117 noise, t_scan_min_ns_,
118 t_scan_max, t_scan_step_ns_);
119 const auto fit = fitter.
fit(samples);
122 ldmx_log(trace) <<
"fit feb=" <<
static_cast<int>(feb)
123 <<
" hyb=" <<
static_cast<int>(hybrid)
124 <<
" pch=" << pchannel <<
" nsamp=" << n_samples
125 <<
" noise=" << noise
126 <<
" -> converged=" << (fit.converged ?
"yes" :
"no")
127 <<
" amp=" << fit.amplitude <<
" t0=" << fit.t0 <<
"ns"
128 <<
" chi2/ndf=" << fit.chi2 <<
"/" << fit.ndf <<
" ("
129 << (fit.ndf > 0 ? fit.chi2 / fit.ndf : 0.0) <<
")";
131 if (!fit.converged) {
136 if (max_chi2_ndf_ > 0.0 && fit.ndf > 0) {
137 if (fit.chi2 / fit.ndf > max_chi2_ndf_) {
144 sensor.layer_id_, strip_id,
static_cast<float>(fit.amplitude),
145 static_cast<float>(fit.t0),
static_cast<float>(fit.chi2), fit.ndf,
151 ldmx_log(debug) <<
"Produced " << hits.size() <<
" FittedSiStripHits from "
152 << waveforms.size() <<
" waveforms";
154 event.add(output_collection_, hits);
159 const double fail_pct =
165 <<
" failed (" << fail_pct <<
"%)";
166 ldmx_log(info) <<
"SiStripWaveformFitProcessor summary: " <<
n_waveforms_
172 ldmx_log(warn) <<
" unmapped feb=" << (k >> 8) <<
" hybrid=" << (k & 0xFF)
173 <<
": " << n <<
" waveforms dropped";
#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.
Class encapsulating parameters for configuring a processor.
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Fits a pulse shape to the ADC samples of a single silicon-strip readout channel to extract hit amplit...
FitResult fit(const std::vector< short > &samples) const
Fit the pulse to the given ADC sample vector.
const SensorInfo & at(uint8_t feb, uint8_t hybrid) const
Look up the sensor read by (feb, hybrid).
std::size_t size() const
Number of sensors in the map.
bool has(uint8_t feb, uint8_t hybrid) const
True if the map has an entry for this electronics sensor.
static TrackerDaqMap fromJsonFile(const std::string &path)
Load a DAQ map from a JSON file.
static const std::string CONDITIONS_NAME
Name of the conditions object (must match the python registration).
constexpr int stripId(int16_t pchannel, int n_strips, int first_strip, bool reversed)
Map a physical strip number (pchannel) onto a sensor strip index using a DAQ-map transform: an option...
constexpr void apvChannelFromPchannel(int16_t pchannel, uint8_t &apv_id, uint8_t &channel)
Inverse of pchannel(): recover the (APV id, APV channel) pair from a physical strip number.