REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestRawPeaksFinderProcess.cxx
1
2#include "TRestRawPeaksFinderProcess.h"
3
4#include <utility>
5
7
8using namespace std;
9
11
13 fInputEvent = dynamic_cast<TRestRawSignalEvent*>(inputEvent);
14
15 const auto run = GetRunInfo();
16 if (run != nullptr) {
17 fInputEvent->InitializeReferences(run);
18 }
19
20 if (fReadoutMetadata == nullptr) {
21 fReadoutMetadata = fInputEvent->GetReadoutMetadata();
22 }
23
24 if (fReadoutMetadata == nullptr && !fChannelTypes.empty()) {
25 cerr << "TRestRawPeaksFinderProcess::ProcessEvent: readout metadata is null, cannot filter "
26 "the process by signal type"
27 << endl;
28 exit(1);
29 }
30
31 vector<tuple<UShort_t, UShort_t, double, double>>
32 eventPeaks; // signalId, time, amplitude, amplitudeBaseLineCorrected
33
34 // Calculate average baseline and sigma of all the TPC signals
35 double BaseLineMean = 0.0;
36 double BaseLineSigmaMean = 0.0;
37 unsigned int countTPC = 0;
38
39 for (int signalIndex = 0; signalIndex < fInputEvent->GetNumberOfSignals(); signalIndex++) {
40 const auto signal = fInputEvent->GetSignal(signalIndex);
41 const UShort_t signalId = signal->GetSignalID();
42
43 const string channelType = fReadoutMetadata->GetTypeForChannelDaqId(signalId);
44 const string channelName = fReadoutMetadata->GetNameForChannelDaqId(signalId);
45
46 // Check if channel type is in the list of selected channel types
47 if (fChannelTypes.find(channelType) == fChannelTypes.end()) {
48 continue;
49 }
50
51 // Choose appropriate function based on channel type
52 if (channelType == "tpc") {
53 signal->CalculateBaseLine(fBaselineRange.X(), fBaselineRange.Y());
54 // Accumulate the baseline and sigma values
55 BaseLineMean += signal->GetBaseLine();
56 BaseLineSigmaMean += signal->GetBaseLineSigma();
57 countTPC++; // Count the signals considered
58 }
59 }
60
61 // Calculate the average if there were any matching signals
62 if (countTPC > 0) {
63 BaseLineMean /= countTPC;
64 BaseLineSigmaMean /= countTPC;
65 }
66
67 for (int signalIndex = 0; signalIndex < fInputEvent->GetNumberOfSignals(); signalIndex++) {
68 const auto signal = fInputEvent->GetSignal(signalIndex);
69 const UShort_t signalId = signal->GetSignalID();
70
71 const string channelType = fReadoutMetadata->GetTypeForChannelDaqId(signalId);
72 const string channelName = fReadoutMetadata->GetNameForChannelDaqId(signalId);
73
74 // check if channel type is in the list of selected channel types
75 if (fChannelTypes.find(channelType) == fChannelTypes.end()) {
76 continue;
77 }
78
79 // Choose appropriate function based on channel type
80 if (channelType == "tpc") {
81 signal->CalculateBaseLine(fBaselineRange.X(), fBaselineRange.Y());
82 double signalBaseLine = signal->GetBaseLine();
83
84 // I think count will never be 0, just in case
85 if (countTPC <= 0) {
86 cerr << "TRestRawPeaksFinderProcess::ProcessEvent: TPC count is 0 in TPC loop, this should "
87 "not happen"
88 << endl;
89 exit(1);
90 }
91
92 const double threshold = BaseLineMean + fSigmaOverBaseline * BaseLineSigmaMean;
93 const auto peaks = signal->GetPeaks(threshold, fDistance, signalBaseLine);
94
95 for (const auto& [time, amplitude, amplitudeBaseLineCorrected] : peaks) {
96 eventPeaks.emplace_back(signalId, time, amplitude, amplitudeBaseLineCorrected);
97 }
98 } else if (channelType == "veto") {
99 // For veto signals the baseline is calculated over the whole range, as we donĀ“t know where the
100 // signal will be.
101 signal->CalculateBaseLine(0, 511, "OUTLIERS");
102 double signalBaseLine = signal->GetBaseLine();
103 // For veto signals the threshold is selected by the user.
104 const auto peaks =
105 signal->GetPeaksVeto(signalBaseLine + fThresholdOverBaseline, fDistance, signalBaseLine);
106
107 for (const auto& [time, amplitude, amplitudeBaseLineCorrected] : peaks) {
108 eventPeaks.emplace_back(signalId, time, amplitude, amplitudeBaseLineCorrected);
109 }
110 }
111 }
112
113 // sort eventPeaks by time, then signal id
114 sort(eventPeaks.begin(), eventPeaks.end(),
115 [](const tuple<UShort_t, UShort_t, double, double>& a,
116 const tuple<UShort_t, UShort_t, double, double>& b) {
117 return tie(get<1>(a), get<0>(a)) < tie(get<1>(b), get<0>(b));
118 });
119
120 vector<UShort_t> peaksChannelId;
121 vector<UShort_t> peaksTime;
122 vector<double> peaksAmplitude;
123 vector<double> peaksAmplitudeBaseLineCorrected;
124
125 double peaksEnergy = 0.0;
126 double peaksEnergyBaseLineCorrected = 0.0;
127 UShort_t peaksCount = 0;
128 UShort_t peaksCountUnique = 0;
129
130 set<UShort_t> uniquePeaks;
131 for (const auto& [channelId, time, amplitude, amplitudeBaseLineCorrected] : eventPeaks) {
132 peaksChannelId.push_back(channelId);
133 peaksTime.push_back(time);
134 peaksAmplitude.push_back(amplitude);
135 peaksAmplitudeBaseLineCorrected.push_back(amplitudeBaseLineCorrected);
136
137 peaksEnergy += amplitude;
138 peaksEnergyBaseLineCorrected += amplitudeBaseLineCorrected;
139 peaksCount++;
140
141 if (uniquePeaks.find(channelId) == uniquePeaks.end()) {
142 uniquePeaks.insert(channelId);
143 peaksCountUnique++;
144 }
145 }
146
147 SetObservableValue("peaksChannelId", peaksChannelId);
148 SetObservableValue("peaksTimeBin", peaksTime);
149 SetObservableValue("peaksAmplitudeADC", peaksAmplitude);
150 SetObservableValue("peaksAmplitudeBaseLineCorrectedADC", peaksAmplitudeBaseLineCorrected);
151
152 SetObservableValue("peaksAmplitudeADCSum", peaksEnergy);
153 SetObservableValue("peaksAmplitudeBaseLineCorrectedADCSum", peaksEnergyBaseLineCorrected);
154 SetObservableValue("peaksCount", peaksCount);
155 SetObservableValue("peaksCountUnique", peaksCountUnique);
156
157 vector<UShort_t> windowPeakIndex(eventPeaks.size(), std::numeric_limits<UShort_t>::max());
158 vector<UShort_t> windowPeakCenter(eventPeaks.size(), 0);
159 vector<UShort_t> windowPeakMultiplicity(eventPeaks.size(), 0);
160
161 UShort_t window_index = 0;
162 for (size_t peakIndex = 0; peakIndex < eventPeaks.size(); peakIndex++) {
163 const auto& [channelId, time, amplitude, amplitudeBaseLineCorrected] = eventPeaks[peakIndex];
164 const auto windowTimeStart = time - fWindow / 2;
165 const auto windowTimeEnd = time + fWindow / 2;
166
167 // check if the peak is already in a window
168 if (windowPeakIndex[peakIndex] != std::numeric_limits<UShort_t>::max()) {
169 continue;
170 }
171
172 UShort_t window_center_time = time;
173
174 set<UShort_t> windowPeaksIndex;
175
176 // add the peak to the window
177 windowPeaksIndex.insert(peakIndex);
178
179 // add the peaks that are in the window
180 for (size_t otherPeakIndex = peakIndex + 1; otherPeakIndex < eventPeaks.size(); otherPeakIndex++) {
181 const auto& [otherChannelId, otherTime, otherAmplitude, otherAmplitudeBaseLineCorrected] =
182 eventPeaks[otherPeakIndex];
183
184 if (otherTime < windowTimeStart) {
185 continue;
186 }
187
188 if (otherTime > windowTimeEnd) {
189 break;
190 }
191
192 windowPeaksIndex.insert(otherPeakIndex);
193 }
194
195 for (const auto& index : windowPeaksIndex) {
196 windowPeakIndex[index] = window_index;
197 windowPeakCenter[index] = window_center_time;
198 windowPeakMultiplicity[index] = windowPeaksIndex.size();
199 }
200
201 window_index++;
202 }
203
204 SetObservableValue("windowPeakIndex", windowPeakIndex);
205 SetObservableValue("windowPeakTimeBin", windowPeakCenter);
206 SetObservableValue("windowPeakMultiplicity", windowPeakMultiplicity);
207
208 vector<UShort_t> windowCenter;
209 vector<UShort_t> windowMultiplicity;
210
211 set<UShort_t> windowPeaksIndexInserted;
212 for (size_t peakIndex = 0; peakIndex < eventPeaks.size(); peakIndex++) {
213 const auto& window_peak_index = windowPeakIndex[peakIndex];
214 if (windowPeaksIndexInserted.find(window_peak_index) != windowPeaksIndexInserted.end()) {
215 continue;
216 }
217
218 windowPeaksIndexInserted.insert(window_peak_index);
219
220 windowCenter.push_back(windowPeakCenter[peakIndex]);
221 windowMultiplicity.push_back(windowPeakMultiplicity[peakIndex]);
222 }
223
224 SetObservableValue("windowTimeBin", windowCenter);
225 SetObservableValue("windowMultiplicity", windowMultiplicity);
226
227 if (fTimeBinToTimeFactorMultiplier != 0.0) {
228 vector<Double_t> windowCenterTime(windowCenter.size(), 0.0);
229 vector<Double_t> windowPeakCenterTime(windowPeakCenter.size(), 0.0);
230 vector<Double_t> peaksTimePhysical(peaksTime.size(), 0.0);
231
232 // lambda to convert time bin to time
233 auto timeBinToTime = [this](UShort_t timeBin) {
234 if (!fTimeConversionElectronics) {
235 return fTimeBinToTimeFactorMultiplier * timeBin - fTimeBinToTimeFactorOffset;
236 } else {
237 // @jporron
238 double zero = -1 + (512 * fTimeBinToTimeFactorMultiplier - fTimeBinToTimeFactorOffset -
239 fTimeBinToTimeFactorOffsetTCM) /
240 fTimeBinToTimeFactorMultiplier;
241 return fTimeBinToTimeFactorMultiplier * (timeBin - zero);
242 }
243 };
244
245 for (size_t i = 0; i < windowCenter.size(); i++) {
246 windowCenterTime[i] = timeBinToTime(windowCenter[i]);
247 }
248
249 for (size_t i = 0; i < windowPeakCenter.size(); i++) {
250 windowPeakCenterTime[i] = timeBinToTime(windowPeakCenter[i]);
251 }
252
253 for (size_t i = 0; i < peaksTime.size(); i++) {
254 peaksTimePhysical[i] = timeBinToTime(peaksTime[i]);
255 }
256
257 SetObservableValue("windowTime", windowCenterTime);
258 SetObservableValue("windowPeakTime", windowPeakCenterTime);
259 SetObservableValue("peaksTime", peaksTimePhysical);
260 }
261
262 if (fADCtoEnergyFactor != 0.0 || !fChannelIDToADCtoEnergyFactor.empty()) {
263 vector<Double_t> peaksEnergyPhysical(peaksAmplitudeBaseLineCorrected.size(), 0.0);
264 Double_t peaksEnergySum = 0.0;
265
266 if (fADCtoEnergyFactor != 0.0) {
267 // same factor for all peaks
268 for (size_t i = 0; i < peaksAmplitude.size(); i++) {
269 peaksEnergyPhysical[i] = peaksAmplitudeBaseLineCorrected[i] * fADCtoEnergyFactor;
270 peaksEnergySum += peaksEnergyPhysical[i];
271 }
272 } else {
273 // use map to get factor for each channel
274 for (size_t i = 0; i < peaksAmplitude.size(); i++) {
275 const auto channelId = peaksChannelId[i];
276 // check if the channel is in the map
277 if (fChannelIDToADCtoEnergyFactor.find(channelId) == fChannelIDToADCtoEnergyFactor.end()) {
278 cerr << "TRestRawPeaksFinderProcess::ProcessEvent: channel id " << channelId
279 << " not found in the map of ADC to energy factors" << endl;
280 exit(1);
281 }
282 const auto factor = fChannelIDToADCtoEnergyFactor[channelId];
283
284 peaksEnergyPhysical[i] = peaksAmplitudeBaseLineCorrected[i] * factor;
285 peaksEnergySum += peaksEnergyPhysical[i];
286 }
287 }
288
289 SetObservableValue("peaksEnergy", peaksEnergyPhysical);
290 SetObservableValue("peaksEnergySum", peaksEnergySum);
291 }
292
293 // Remove peak-less veto signals after the peak finding if chosen
295 set<UShort_t> peakSignalIds;
296 for (const auto& [channelId, time, amplitude, amplitudeBaseLineCorrected] : eventPeaks) {
297 peakSignalIds.insert(channelId);
298 }
299
300 vector<UShort_t> signalsToRemove;
301 for (int signalIndex = 0; signalIndex < fInputEvent->GetNumberOfSignals(); signalIndex++) {
302 const auto signal = fInputEvent->GetSignal(signalIndex);
303 const UShort_t signalId = signal->GetSignalID();
304 const string signalType = fReadoutMetadata->GetTypeForChannelDaqId(signalId);
305
306 if (signalType == "veto" && peakSignalIds.find(signalId) == peakSignalIds.end()) {
307 signalsToRemove.push_back(signalId);
308 }
309 }
310
311 // Now remove all veto signals identified
312 for (const auto& signalId : signalsToRemove) {
313 fInputEvent->RemoveSignalWithId(signalId);
314 }
315 }
316
317 // Remove all veto signals after the peak finding if chosen
318 if (fRemoveAllVetoes) {
319 vector<UShort_t> signalsToRemove;
320 for (int signalIndex = 0; signalIndex < fInputEvent->GetNumberOfSignals(); signalIndex++) {
321 const auto signal = fInputEvent->GetSignal(signalIndex);
322 const UShort_t signalId = signal->GetSignalID();
323 const string signalType = fReadoutMetadata->GetTypeForChannelDaqId(signalId);
324
325 if (signalType == "veto") {
326 signalsToRemove.push_back(signalId);
327 }
328 }
329
330 // Now remove all veto signals identified
331 for (const auto& signalId : signalsToRemove) {
332 fInputEvent->RemoveSignalWithId(signalId);
333 }
334 }
335
336 return inputEvent;
337}
338
339std::map<UShort_t, double> parseStringToMap(const std::string& input) {
340 std::map<UShort_t, double> my_map;
341 std::string cleaned_input;
342
343 // Step 1: Clean the input to remove curly braces and spaces
344 for (char c : input) {
345 if (!std::isspace(c) && c != '{' && c != '}') {
346 cleaned_input += c;
347 }
348 }
349
350 // Step 2: Parse each key-value pair
351 std::stringstream ss(cleaned_input);
352 std::string pair;
353 while (std::getline(ss, pair, ',')) {
354 // Find the colon to split key and value
355 size_t colon_pos = pair.find(':');
356 if (colon_pos != std::string::npos) {
357 // Extract and convert key and value
358 int key = std::stoi(pair.substr(0, colon_pos));
359 double value = std::stod(pair.substr(colon_pos + 1));
360 my_map[key] = value;
361 }
362 }
363
364 return my_map;
365}
366
368 const auto filterType = GetParameter("channelType", "");
369 if (!filterType.empty()) {
370 fChannelTypes.insert(filterType);
371 }
372
373 if (fChannelTypes.empty()) {
374 // if no channel type is specified, use all channel types
375 }
376
377 fThresholdOverBaseline = GetDblParameterWithUnits("thresholdOverBaseline", fThresholdOverBaseline);
378 fSigmaOverBaseline = GetDblParameterWithUnits("sigmaOverBaseline", fSigmaOverBaseline);
379 fBaselineRange = Get2DVectorParameterWithUnits("baselineRange", fBaselineRange);
380 fDistance = UShort_t(GetDblParameterWithUnits("distance", fDistance));
381 fWindow = UShort_t(GetDblParameterWithUnits("window", fWindow));
382 fRemoveAllVetoes = StringToBool(GetParameter("removeAllVetoes", fRemoveAllVetoes));
383 fRemovePeaklessVetoes = StringToBool(GetParameter("removePeaklessVetoes", fRemovePeaklessVetoes));
384
385 fTimeBinToTimeFactorMultiplier = GetDblParameterWithUnits("sampling", fTimeBinToTimeFactorMultiplier);
386 fTimeBinToTimeFactorOffset = GetDblParameterWithUnits("trigDelay", fTimeBinToTimeFactorOffset);
387 fTimeBinToTimeFactorOffsetTCM = GetDblParameterWithUnits("trigDelayTCM", fTimeBinToTimeFactorOffsetTCM);
388 fTimeConversionElectronics =
389 StringToBool(GetParameter("trigDelayElectronics", fTimeConversionElectronics));
390
391 fADCtoEnergyFactor = GetDblParameterWithUnits("adcToEnergyFactor", fADCtoEnergyFactor);
392 const string fChannelIDToADCtoEnergyFactorAsString = GetParameter("channelIDToADCtoEnergyFactor", "");
393 if (!fChannelIDToADCtoEnergyFactorAsString.empty()) {
394 // map should be in the format: "{channelId1: factor1, channelId2: factor2, ...}" (spaces are allowed
395 // but not required)
396 fChannelIDToADCtoEnergyFactor = parseStringToMap(fChannelIDToADCtoEnergyFactorAsString);
397 }
398
399 if (fADCtoEnergyFactor != 0 && !fChannelIDToADCtoEnergyFactor.empty()) {
400 cerr << "TRestRawPeaksFinderProcess::InitFromConfigFile: both adcToEnergyFactor and "
401 "channelIDToADCtoEnergyFactor are defined. Please, remove one of them."
402 << endl;
403 exit(1);
404 }
405
406 if (fBaselineRange.X() > fBaselineRange.Y() || fBaselineRange.X() < 0 || fBaselineRange.Y() < 0) {
407 cerr << "TRestRawPeaksFinderProcess::InitProcess: baseline range is not sorted or < 0" << endl;
408 exit(1);
409 }
410
411 if (fThresholdOverBaseline < 0) {
412 cerr << "TRestRawPeaksFinderProcess::InitProcess: threshold over baseline is < 0" << endl;
413 exit(1);
414 }
415
416 if (fSigmaOverBaseline < 0) {
417 cerr << "TRestRawPeaksFinderProcess::InitProcess: sigma over baseline is < 0" << endl;
418 exit(1);
419 }
420
421 if (fDistance <= 0) {
422 cerr << "TRestRawPeaksFinderProcess::InitProcess: distance is < 0" << endl;
423 exit(1);
424 }
425
426 if (fWindow <= 0) {
427 cerr << "TRestRawPeaksFinderProcess::InitProcess: window is < 0" << endl;
428 exit(1);
429 }
430
431 if (filterType != "veto" && fRemovePeaklessVetoes) {
432 cerr << "TRestRawPeaksFinderProcess::InitProcess: removing veto signals only makes sense when the "
433 "process is applied to veto signals. Remove \"removePeaklessVetoes\" parameter"
434 << endl;
435 exit(1);
436 }
437}
438
441
442 RESTMetadata << "Applying process to channel types: ";
443 for (const auto& type : fChannelTypes) {
444 RESTMetadata << type << " ";
445 }
446 RESTMetadata << RESTendl;
447
448 RESTMetadata << "Baseline range for tpc signals: " << fBaselineRange.X() << " - " << fBaselineRange.Y()
449 << RESTendl;
450 RESTMetadata << "Sigma over baseline for tpc signals: " << fSigmaOverBaseline << RESTendl;
451
452 RESTMetadata << "Threshold over baseline for veto signals: " << fThresholdOverBaseline << RESTendl;
453
454 RESTMetadata << "Distance: " << fDistance << RESTendl;
455 RESTMetadata << "Window: " << fWindow << RESTendl;
456
457 EndPrintProcess();
458}
TRestRun * GetRunInfo() const
Return the pointer of the hosting TRestRun object.
void BeginPrintProcess()
[name, cut range]
void SetObservableValue(const std::string &name, const T &value)
Set observable value for AnalysisTree.
A base class for any REST event.
Definition: TRestEvent.h:38
virtual void InitializeReferences(TRestRun *run)
Initialize dynamical references when loading the event from a root file.
Definition: TRestEvent.cxx:175
endl_t RESTendl
Termination flag object for TRestStringOutput.
std::string GetParameter(std::string parName, TiXmlElement *e, TString defaultValue=PARAMETER_NOT_FOUND_STR)
Returns the value for the parameter named parName in the given section.
Double_t fSigmaOverBaseline
choose times the sigma of the baseline must be overcome to consider a peak
UShort_t fDistance
distance between two peaks to consider them as different (ADC units)
void InitFromConfigFile() override
To make settings from rml file. This method must be implemented in the derived class.
Bool_t fRemovePeaklessVetoes
option to remove peak-less veto signals after finding the peaks
Double_t fThresholdOverBaseline
threshold over baseline to consider a peak
UShort_t fWindow
window size to calculate the peak amplitude (time bins)
void InitProcess() override
To be executed at the beginning of the run (outside event loop)
TRestEvent * ProcessEvent(TRestEvent *inputEvent) override
Process one event.
TVector2 fBaselineRange
range of samples to calculate baseline for peak finding
void PrintMetadata() override
Implemented it in the derived metadata class to print out specific metadata information.
Bool_t fRemoveAllVetoes
option to remove all veto signals after finding the peaks
An event container for time rawdata signals with fixed length.
Int_t GetSignalID() const
Returns the value of signal ID.