LDMX Software
trigscint::EventReadoutProducer Class Reference

Linearizes ADC info to charge, calculates channel pedestal and noise levels (in charge) More...

#include <EventReadoutProducer.h>

Public Member Functions

 EventReadoutProducer (const std::string &name, framework::Process &process)
 
void configure (framework::config::Parameters &parameters) override
 Callback for the processor 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.
 
- 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.
 
virtual void onProcessEnd ()
 Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.
 
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

bool verbose_ {false}
 Class to set the verbosity level.
 
std::string input_collection_
 Name of the input collection containing the sim hits.
 
std::string input_pass_name_
 Name of the pass that the input collection is on (empty string means take any pass)
 
std::string output_collection_
 Name of the output collection that will be used to stored the digitized trigger scintillator hits.
 
int n_ped_samples_ {5}
 Number of initial time samples averaged over in the pedestal calculation.
 
int time_shift_ {5}
 Number of time samples to shift readout by, to align fibers if there is an offset.
 
int fiber_to_shift_ {1}
 Which of the fibers to set the time shift for (0 or 1)
 

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
 
NtupleManager & ntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Linearizes ADC info to charge, calculates channel pedestal and noise levels (in charge)

Definition at line 30 of file EventReadoutProducer.h.

Constructor & Destructor Documentation

◆ EventReadoutProducer()

trigscint::EventReadoutProducer::EventReadoutProducer ( const std::string & name,
framework::Process & process )

Definition at line 11 of file EventReadoutProducer.cxx.

13 : Producer(name, process) {}
Producer(const std::string &name, Process &process)
Class constructor.
virtual void process(Event &event) final
Processing an event for a Producer is calling produce.

Member Function Documentation

◆ configure()

void trigscint::EventReadoutProducer::configure ( framework::config::Parameters & parameters)
overridevirtual

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

Parameters
parametersParameterSet for configuration.

Reimplemented from framework::EventProcessor.

Definition at line 15 of file EventReadoutProducer.cxx.

16 {
17 // Configure this instance of the producer
18 input_collection_ = parameters.get<std::string>("input_collection");
19 input_pass_name_ = parameters.get<std::string>("input_pass_name");
20 output_collection_ = parameters.get<std::string>("output_collection");
21 n_ped_samples_ = parameters.get<int>("number_pedestal_samples");
22 time_shift_ = parameters.get<int>("time_shift");
23 fiber_to_shift_ = parameters.get<int>("fiber_to_shift");
24 verbose_ = parameters.get<bool>("verbose");
25
26 ldmx_log(debug) << "In configure, got parameters:" << "\noutput_collection = "
28 << "\ninput_collection = " << input_collection_
29 << "\ninput_pass_name = " << input_pass_name_
30 << "\nnumber_pedestal_samples = " << n_ped_samples_
31 << "\ntime_shift = " << time_shift_
32 << "\nfiber_to_shift = " << fiber_to_shift_
33 << "\nverbose = " << verbose_;
34}
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
bool verbose_
Class to set the verbosity level.
std::string output_collection_
Name of the output collection that will be used to stored the digitized trigger scintillator hits.
std::string input_pass_name_
Name of the pass that the input collection is on (empty string means take any pass)
int time_shift_
Number of time samples to shift readout by, to align fibers if there is an offset.
int fiber_to_shift_
Which of the fibers to set the time shift for (0 or 1)
std::string input_collection_
Name of the input collection containing the sim hits.
int n_ped_samples_
Number of initial time samples averaged over in the pedestal calculation.

References framework::config::Parameters::get().

◆ produce()

void trigscint::EventReadoutProducer::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 36 of file EventReadoutProducer.cxx.

36 {
37 // initialize QIE object for linearizing ADCs
38 SimQIE qie;
39
40 const auto digis{event.getCollection<trigscint::TrigScintQIEDigis>(
42
43 std::vector<trigscint::EventReadout> channel_readout_events;
44 for (const auto& digi : digis) {
46 auto adc{digi.getADC()};
47 auto tdc{digi.getTDC()};
48
49 // copy over from qie digi for convenience
50 out_event.setChanID(digi.getChanID());
51 out_event.setElecID(digi.getElecID());
52 out_event.setTimeSinceSpill(digi.getTimeSinceSpill());
53 // elecID increases monotonically with 8 channels per fiber
54 out_event.setFiberNb(digi.getElecID() / 8);
55 if (out_event.getFiberNb() == fiber_to_shift_)
56 out_event.setTimeOffset(time_shift_);
57
58 out_event.setADC(adc);
59 out_event.setTDC(tdc);
60 std::vector<float> charge;
61 std::vector<float> charge_err;
62
63 float avg_q = 0;
64 float tot_pos_q = 0;
65 int i_s = 0;
66 [[maybe_unused]] int n_pos = 0;
67 float early_ped = 0;
68 for (auto& val : adc) {
69 float q = qie.adc2Q(val);
70 charge.push_back(q);
71 charge_err.push_back(qie.qErr(q));
72 avg_q += q; // charge.back();
73 if (q > 0) {
74 tot_pos_q += q;
75 n_pos++;
76 }
77 if (verbose_)
78 ldmx_log(debug) << "got adc value " << val << " and charge "
79 << q; // qie.ADC2Q(val);
80 if (i_s < n_ped_samples_) early_ped += q;
81 i_s++;
82 }
83 out_event.setQ(charge); // set in proper order before sorting
84 out_event.setQError(charge_err); // set in proper order before sorting
85 early_ped /= n_ped_samples_;
86 out_event.setEarlyPedestal(early_ped);
87
88 // oscillation check. for this the pulse charge needs to be in order, so set
89 // this up now the period is 4. ansatz: an oscillation is a repeated shape.
90 // normalize to maxq=1, in every interval of 4 samples if after
91 // normalization the same numbers are repeated, it's an oscillation edge
92 // case: multiple single PE peaks with that repetition. we probably don't
93 // need to keep those anyway
94 std::vector<float> charge_check = {NULL};
95 float min_charge = 10;
96 // no point in looking at oscillations just around the pedestal.
97 // nearest edge is 10.35 fC //ADC=0 corresponds to -16 fC.
98 float ped = 0;
99 int ped_length = (int)charge.size() / 5;
100 // actually pulse can be up to 12 samples = 2/5*30
101 int ped_offset = 2;
102 // but still skip the lowest (and highest) few
103 // for (int i = pedLength; i < 3*pedLength ; i++) {
105 if (charge.size() > 8) {
106 if (verbose_) ldmx_log(debug) << "going into oscillations check ";
107 for (int i = 3; i < charge.size() - 4; i++) {
108 float max_samp = min_charge;
109 for (int i_q = 0; i_q < 4;
110 i_q++) { // find the local max in the 4 samples
111 // ldmx_log(debug) << "got charge " << charge[i+iQ];
112 if (charge[i + i_q] > max_samp) max_samp = charge[i + i_q];
113 }
114 if (verbose_) ldmx_log(debug) << "got max charge " << max_samp;
115 for (int i_q = 0; i_q < 4; i_q++) // store the locally normalized
116 // numbers. even if the period is
117 // 5 this should work for a while
118 charge_check.push_back(charge[i + i_q] / max_samp);
119 i += 3; // to increment by 4, do 3 here and 1 in the loop
120 }
121 }
122 if (ped_length > 4) {
123 // now calculate the pedestal as the average of the middle half of the
124 // sorted vector
125 std::sort(charge.begin(), charge.end());
126 for (int i = ped_offset; i < 2 * ped_length + ped_offset;
127 i++) { // use 1st and 2nd 5th
128 ped += charge[i];
129 }
130 ped /= 2 * ped_length;
131 }
132 // median: technically only true for odd number of elements but good enough
133 float med_q = charge[(int)charge.size() / 2];
134 float min_q = charge[0];
135 float max_q = charge[charge.size() - 1];
136
137 out_event.setTotQ(tot_pos_q);
138 //-nPos*ped); //store (event) ped subtracted
139 // total charge, before dividing by N -->
140 // actually, ped subtraction makes it confusing
141 // outEvent.setTotQ(totPosQ-adc.size()*ped); //store (event) ped subtracted
142 // total charge, before dividing by N
143 // outEvent.setTotQ(avgQ-adc.size()*ped);
145 avg_q /= adc.size();
146 out_event.setPedestal(ped);
147 out_event.setAvgQ(avg_q);
148 out_event.setMedQ(med_q);
149 out_event.setMinQ(min_q);
150 out_event.setMaxQ(max_q);
151
152 // and the noise as the RMSE of that, same interval as pedestal
153 float diff_sq = 0;
154 // for (int i = pedLength; i < 3*pedLength ; i++) {
155 if (charge.size() > 8) {
156 for (int i = ped_offset; i < 2 * ped_length + ped_offset; i++) {
157 diff_sq += (charge[i] - ped) * (charge[i] - ped);
158 }
159 diff_sq /= 2 * ped_length; // adc.size();
160 }
161 out_event.setNoise(sqrt(diff_sq));
162
163 // oscillation check
164 uint flag_oscillation = 0;
165 if (charge.size() > 8) {
166 // no need to run tedious oscillation check for all-neg channels
167 if (max_q > min_charge) {
168 int max_id = 0;
169 // find the first occurence of a local max
170 for (int i = 0; i < charge_check.size() - 4; i++) {
171 if (charge_check[i] ==
172 1) { // an actual local max has been normalised by its own value
173 max_id = i;
174 // ldmx_log(debug) << "storing max index " <<maxID <<"
175 // and size of vector is " << chargeCheck.size()-4;
176 break;
177 }
178 }
179 int last_match_sample = 0;
180 // start from local max
181 bool do_break = false;
182 for (int i = max_id; i < charge_check.size() - 4; i++) {
183 if (verbose_)
184 ldmx_log(debug)
185 << "Checking how many matching groups of four we can "
186 "find, starting at index "
187 << i;
188
189 for (int i_q = 0; i_q < 4; i_q++) { // check if they are consistently
190 // close
191 if (verbose_)
192 ldmx_log(debug)
193 << "Comparing " << charge_check[i + i_q] << " (sample "
194 << i + i_q << ") to " << charge_check[i + 4 + i_q]
195 << " (sample " << i + 4 + i_q << "), ratio is "
196 << charge_check[i + i_q] / charge_check[i + 4 + i_q];
197 // we can be generous in these crietira since we will require an
198 // unbroken suite of 8 matches to call it oscillation
199 if (fabs(charge_check[i + i_q] / charge_check[i + 4 + i_q] - 1) <
200 0.5 || // need this tolerance to be kind of large, most
201 // actual peaks won't pass it by far anyway.
202 (charge_check[i + 4 + i_q] < 0.01 &&
203 fabs(charge_check[i + i_q] / charge_check[i + 4 + i_q]) <
204 5)) // for very small numbers, one ADC difference can be a
205 // factor 3 so add some margin
206 last_match_sample = i + i_q;
207 else {
208 if (verbose_)
209 ldmx_log(debug)
210 << "Oscillation check for channel " << digi.getChanID()
211 << " breaking at time sample " << i + i_q;
212 do_break = true; // break outer loop
213 break; // break this loop
214 }
215 }
216 if (do_break) {
217 break;
218 }
219 if (verbose_)
220 ldmx_log(debug) << "Current lastMatchSample " << last_match_sample;
221 if (last_match_sample - max_id >= 2 * 4) {
222 // we had at least a couple of oscillations (2nd period
223 // was fully matched by third)
224 flag_oscillation = 1; // there is another check possible later too,
225 // commented for now
226 break; // we've seen what we need to see
227 }
228 i += 3;
229 }
230 } // if positive maxQ
231 }
232 // //use the top and bottom ends of the sorted q as another oscillation
233 // catcher: we don't expect that the top values will be high and basically
234 // identical unless they are from an oscillation
235 int n_high = 0;
236 int quart_length = (int)charge.size() / 4;
237 for (int i = 4 * quart_length - 2; i >= 3 * quart_length; i--) {
238 // maxQ is already at last index
239 if (charge[i] / max_q > 0.66) n_high++;
240 }
241
242 /* used to be: >0.9, > 0.25. But this really killed MC pulses which
243 all end up in 0.90-0.94, and somewhere >0.05 (at least >0.15)
244 */
245 uint flag_spike = (max_q / out_event.getTotQ() > 0.95) ||
246 (charge[charge.size() - 2] / max_q < 0.05);
247 // skip "unnaturally" narrow hits (all charge in
248 // one sample or huge drop to second highest)
249 uint flag_plateau = (ped > 15 || n_high >= 5);
250 //( fabs(ped) > 15 ); //threshold // //skip
251 // events that have strange plateaus
252 uint flag_long_pulse = 0;
253 // easier to deal with in hit reconstruction directly. copy channel
254 // flags to hit flags and add this one there
255 uint flag_noise = (out_event.getNoise() > 3.5 || out_event.getNoise() == 0);
256 // =0 is typically from funky events but
257 // could be too harsh maybe
258 /* //let this wait for now
259 //if we have many high counts, a small event pedestal (where they weren't
260 included), and an avgQ ~ maxQ/nHigh, then this is an oscillation if (
261 (quartLength-nHigh<2 && ped<10) || fabs( maxQ/(avgQ*nHigh)-1 ) <0.1 )
262 flagOscillation=1;
263*/
264
265 /* //this seems to not catch what we want it to
266if ( fabs(chan.getPedestal()) < 15 //threshold // //skip events that have
267strange plateaus
268 // && (chan.getAvgQ()/chan.getPedestal()<0.8) //skip
269events that have strange oscillations
270 && 1 < nSampAboveThr && nSampAboveThr < 10 ) // skip one-time sample
271flips and long weird pulses
272 */
273 uint flag = flag_spike + 2 * flag_plateau + 4 * flag_long_pulse +
274 8 * flag_oscillation + 16 * flag_noise;
275 ldmx_log(debug)
276 << "Got quality flag " << flag
277 << " made up of (spike/plateau/long pulse/oscillation/noise) "
278 << flag_spike << "+" << flag_plateau << "+" << flag_long_pulse << "+"
279 << flag_oscillation << "+" << flag_noise;
280 out_event.setQualityFlag(flag);
281
282 // if (ped > 15 )
283 // continue;
284 ldmx_log(debug) << "In event " << event.getEventHeader().getEventNumber()
285 << ", set pedestal = " << out_event.getPedestal()
286 << // ped <<
287 " fC, noise = " << out_event.getNoise() << " fC for channel "
288 << out_event.getChanID();
289
290 channel_readout_events.push_back(out_event);
291 }
292 // Create the container to hold the
293 // digitized trigger scintillator hits.
294
295 event.add(output_collection_, channel_readout_events);
296 ldmx_log(debug) << "\n";
297}
This class represents the linearised QIE output from the trigger scintillator, in charge (fC).
void setMedQ(const float medQ)
Set channel (linearized, charge-equiv) median charge.
void setFiberNb(const int fiberNb)
Set channel readout fiber number.
void setTimeOffset(const int timeOffset)
Set channel readout itme offset (in units of samples)
float getPedestal() const
Get the pedestal.
void setMinQ(const float minQ)
Set channel (linearized, charge-equiv) minimum charge.
void setQError(const std::vector< float > qErr)
Store charge quantization errors of all time samples.
void setNoise(const float noise)
Set channel (linearized, charge-equiv) noise.
float getNoise() const
Get the channel noise.
void setTotQ(const float totQ)
Set channel (linearized, charge-equiv) average charge.
float getTotQ() const
Get the channel totQ.
void setQualityFlag(const uint flag)
Set channel data quality flag.
void setPedestal(const float pedestal)
Set channel (linearized.
void setAvgQ(const float avgQ)
Set channel (linearized, charge-equiv) average charge.
void setMaxQ(const float maxQ)
Set channel (linearized, charge-equiv) maximum charge.
int getFiberNb() const
Get the channel fiberNb.
void setQ(const std::vector< float > q)
Store charges of all time samples.
void setEarlyPedestal(const float earlyPed)
Set channel (linearized.
class for storing QIE output
void setTDC(const std::vector< int > tdc)
Store tdcs of all time samples.
void setChanID(const int chanid)
Store the channel ID.
void setTimeSinceSpill(const uint32_t timeSpill)
Store the event time since spill counter.
int getChanID() const
Get channel ID.
void setElecID(const int elecid)
Store the electronics ID.
void setADC(const std::vector< int > adc)
Store adcs of all time samples.

References trigscint::SimQIE::adc2Q(), trigscint::TrigScintQIEDigis::getChanID(), trigscint::EventReadout::getFiberNb(), trigscint::EventReadout::getNoise(), trigscint::EventReadout::getPedestal(), trigscint::EventReadout::getTotQ(), trigscint::SimQIE::qErr(), trigscint::TrigScintQIEDigis::setADC(), trigscint::EventReadout::setAvgQ(), trigscint::TrigScintQIEDigis::setChanID(), trigscint::EventReadout::setEarlyPedestal(), trigscint::TrigScintQIEDigis::setElecID(), trigscint::EventReadout::setFiberNb(), trigscint::EventReadout::setMaxQ(), trigscint::EventReadout::setMedQ(), trigscint::EventReadout::setMinQ(), trigscint::EventReadout::setNoise(), trigscint::EventReadout::setPedestal(), trigscint::EventReadout::setQ(), trigscint::EventReadout::setQError(), trigscint::EventReadout::setQualityFlag(), trigscint::TrigScintQIEDigis::setTDC(), trigscint::EventReadout::setTimeOffset(), trigscint::TrigScintQIEDigis::setTimeSinceSpill(), and trigscint::EventReadout::setTotQ().

Member Data Documentation

◆ fiber_to_shift_

int trigscint::EventReadoutProducer::fiber_to_shift_ {1}
private

Which of the fibers to set the time shift for (0 or 1)

Definition at line 70 of file EventReadoutProducer.h.

70{1};

◆ input_collection_

std::string trigscint::EventReadoutProducer::input_collection_
private

Name of the input collection containing the sim hits.

Definition at line 52 of file EventReadoutProducer.h.

◆ input_pass_name_

std::string trigscint::EventReadoutProducer::input_pass_name_
private

Name of the pass that the input collection is on (empty string means take any pass)

Definition at line 56 of file EventReadoutProducer.h.

◆ n_ped_samples_

int trigscint::EventReadoutProducer::n_ped_samples_ {5}
private

Number of initial time samples averaged over in the pedestal calculation.

Definition at line 63 of file EventReadoutProducer.h.

63{5};

◆ output_collection_

std::string trigscint::EventReadoutProducer::output_collection_
private

Name of the output collection that will be used to stored the digitized trigger scintillator hits.

Definition at line 60 of file EventReadoutProducer.h.

◆ time_shift_

int trigscint::EventReadoutProducer::time_shift_ {5}
private

Number of time samples to shift readout by, to align fibers if there is an offset.

Definition at line 67 of file EventReadoutProducer.h.

67{5};

◆ verbose_

bool trigscint::EventReadoutProducer::verbose_ {false}
private

Class to set the verbosity level.

Definition at line 49 of file EventReadoutProducer.h.

49{false};

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