REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestRawSignalRecoverSaturationProcess.cxx
1/*************************************************************************
2 * This file is part of the REST software framework. *
3 * *
4 * Copyright (C) 2016 GIFNA/TREX (University of Zaragoza) *
5 * For more information see http://gifna.unizar.es/trex *
6 * *
7 * REST is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * REST is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have a copy of the GNU General Public License along with *
18 * REST in $REST_PATH/LICENSE. *
19 * If not, see http://www.gnu.org/licenses/. *
20 * For the list of contributors see $REST_PATH/CREDITS. *
21 *************************************************************************/
22
143
144#include "TRestRawSignalRecoverSaturationProcess.h"
145
147
152
157
163 SetSectionName(this->ClassName());
164 SetLibraryVersion(LIBRARY_VERSION);
165 fAnaEvent = NULL;
166
167 // Initialize here the values of class data members if needed
169 fProcessAllSignals = false;
172 fBaseLineRange = TVector2(-1, -1); // -1 means no baseline range
173 fFitRange = TVector2(-1, -1); // -1 means no fit range
174 fInitPointsOverThreshold = TVector3(-1, -1, -1); // -1 means no initialization
175 fC = nullptr;
176}
177
184 // Write here the jobs to do before processing
185 // i.e., initialize histograms and auxiliary vectors,
186 // read TRestRun metadata, or load additional rml sections
188 fC = new TCanvas("c", "c", 800, 600);
189 }
190}
191
196 fAnaEvent = (TRestRawSignalEvent*)evInput;
197 auto eventID = fAnaEvent->GetID();
198
199 // If cut condition matches the event will be not registered.
200 if (ApplyCut()) return nullptr;
201
202 // Write here the main logic of process: TRestRawSignalRecoverSaturationProcess
203 // Read data from input event, write data to output event, and save observables to tree
204
205 RESTDebug << "TRestRawSignalRecoverSaturationProcess::ProcessEvent. Event ID : " << fAnaEvent->GetID()
206 << RESTendl;
207 // observables of the process
208 Double_t addedAmplitude = 0;
209 Double_t addedIntegral = 0;
210 Int_t nSignalsSaturated = 0;
211 Int_t nSignalsRecovered = 0;
212
213 // Set the baseline range if it has been provided
214 if (fBaseLineRange.X() != -1 && fBaseLineRange.Y() != -1)
216 fBaseLineRange.Y()); // this will also calculate the baseline
217
218 // process each signal in the event
219 for (int s = 0; s < fAnaEvent->GetNumberOfSignals(); s++) {
220 TRestRawSignal* signal = fAnaEvent->GetSignal(s);
221 Double_t signalAddedAmplitude = 0;
222
223 // skip signals that are not saturated (if fProcessAllSignals is false)
225 continue;
226 }
227
228 RESTDebug << "Processing signal " << s << " in event " << eventID << RESTendl;
229 nSignalsSaturated++;
230 Int_t maxPeakBin = signal->GetMaxPeakBin();
231 Short_t maxValue = (*signal)[maxPeakBin];
232 std::vector<size_t> saturatedBins;
233
234 if (maxValue < fMinSaturationValue) {
235 RESTDebug << " Saturation value " << maxValue << " is less than the minimum value "
237 continue;
238 }
239
240 // Find all saturated bins
241 for (size_t i = (size_t)maxPeakBin; i < (size_t)signal->GetNumberOfPoints(); i++) {
242 if ((*signal)[i] == maxValue)
243 saturatedBins.push_back(i);
244 else
245 break; // Stop when the signal stops being saturated
246 }
247
248 // If processAllSignals is true, set saturatedBins for all signals
249 if (fProcessAllSignals && saturatedBins.size() < fMinSaturatedBins) {
250 saturatedBins.clear();
251 // set saturated bins around maxPeakBin
252 for (size_t i = maxPeakBin - fNBinsIfNotSaturated / 2;
253 i < maxPeakBin + fNBinsIfNotSaturated / 2 && i < (size_t)signal->GetNumberOfPoints(); i++) {
254 saturatedBins.push_back(i);
255 }
256 // maxPeakBin should be the first saturated bin
257 maxPeakBin = saturatedBins.empty() ? maxPeakBin : saturatedBins.front();
258 maxValue = (*signal)[maxPeakBin];
259 }
260
261 if (!saturatedBins.empty()) {
262 RESTDebug << " Saturated bins:" << saturatedBins.front() << " to " << saturatedBins.back()
263 << " at " << maxValue << RESTendl;
264 }
265
266 // Create TGraph with the not saturated bins for the fit
267 TGraph* g = new TGraph();
268 for (size_t i = 0; i < (size_t)signal->GetNumberOfPoints(); i++) {
269 if (std::find(saturatedBins.begin(), saturatedBins.end(), i) != saturatedBins.end()) continue;
270 g->AddPoint(i, (*signal)[i]);
271 }
272 /* g = signal->GetGraph(); // this would return (*signal)[i]-baseLine (if baseline has been
273 // initialized). Then one should remove the saturated bins from the TGraph:
274 // Remove the saturated bins from the TGraph representing the signal
275 for (size_t i = 0; i < saturatedBins.size(); i++) {
276 g->RemovePoint(maxPeakBin); // when one point is removed the other points are shifted
277 } //*/
278
279 // ShaperSin function (AGET theoretic curve) times logistic function. Better without the sin
280 Double_t startFitRange = 0;
281 Double_t endFitRange = signal->GetNumberOfPoints();
282 if (fFitRange.X() != -1 && fFitRange.Y() != -1) {
283 startFitRange = fFitRange.X();
284 endFitRange = fFitRange.Y();
285 }
286 TF1* f = new TF1("fit",
287 "[0]+[1]*TMath::Exp(-3. * (x-[3])/[2]) * "
288 "(x-[3])/[2] * (x-[3])/[2] * (x-[3])/[2] / "
289 "(1+TMath::Exp(-10000*(x-[3])))",
290 startFitRange, endFitRange);
291
292 // First estimation of the parameters
293 auto peakposEstimate =
294 maxPeakBin + saturatedBins.size() / 2; // maxPeakBin is the first saturated bin
295 Double_t amplEstimate = maxValue;
296 Double_t widthEstimate = (endFitRange - startFitRange) * 0.33; // 0.33 is somehow arbitrary
297 Int_t binAtHalfMaximum = (Int_t)startFitRange;
298 for (size_t i = (size_t)startFitRange; i < (size_t)endFitRange; i++) {
299 if ((*signal)[i] > amplEstimate / 2) {
300 binAtHalfMaximum = i;
301 break;
302 }
303 }
304 widthEstimate =
305 peakposEstimate - binAtHalfMaximum > 0 ? peakposEstimate - binAtHalfMaximum : widthEstimate;
306 Double_t baselineEstimate =
307 (*signal)[0]; // first point of the signal is usually part of the baseline
308 if (signal->isBaseLineInitialized()) { // if the baseline has been initialized, use it
309 baselineEstimate = signal->GetBaseLine();
310 }
311
312 // Second (and better) estimation of amplitude and width. It needs to initialize the points over
313 // threshold
314 Double_t pointThreshold = fInitPointsOverThreshold.X();
315 Double_t signalThreshold = fInitPointsOverThreshold.Y();
316 Int_t pointsOverThreshold = fInitPointsOverThreshold.Z();
317 if (pointsOverThreshold > 0 && pointThreshold > 0 && signalThreshold > 0) {
319 TVector2(pointThreshold, signalThreshold), pointsOverThreshold,
320 signal->GetNumberOfPoints()); // we dont care about overshoot here
321 }
322 auto pOverThreshold = signal->GetPointsOverThreshold();
323 if (!pOverThreshold.empty()) {
324 RESTDebug << " Points over threshold: " << pOverThreshold.size() << ". From point "
325 << pOverThreshold.front() << " to " << pOverThreshold.back() << RESTendl;
326 // extrapolate the line connecting the first point of the pulse peak:
327 // (pOverThreshold[0], signal->GetRawData(pOverThreshold[0]))
328 // with the first point to be saturated: (maxPeakBin, maxValue)
329 // to the peak position (peakposEstimate)
330 amplEstimate = 0.9 * (maxValue - signal->GetRawData(pOverThreshold[0])) /
331 (maxPeakBin - pOverThreshold[0]) * (peakposEstimate - pOverThreshold[0]);
332 // the amplitude estimate should be at least the maximum value of the signal
333 if (amplEstimate < maxValue) amplEstimate = maxValue;
334
335 // estimate the width as the distance between the first pulse point and the
336 // peak position
337 widthEstimate = peakposEstimate - pOverThreshold[0];
338 }
339
340 RESTDebug << " Estimations: ampl=" << amplEstimate << " (" << amplEstimate / 0.0498
341 << ") width=" << widthEstimate << " baseline=" << baselineEstimate
342 << " peakpos=" << peakposEstimate << " (" << peakposEstimate - widthEstimate << ")"
343 << RESTendl;
344 // Configure the fit parameters
345 f->SetParNames("Baseline", "Amplitude*e^{3}", "HalfWidth", "PulseStart");
346 // f->SetParameters(baselineEstimate, amplEstimate / 0.0498, widthEstimate, peakposEstimate -
347 // widthEstimate);
348 // Baseline
349 f->SetParameter(0, baselineEstimate);
350 f->SetParLimits(0, 0, maxValue); // baseline should be positive and less than the saturation value
351 if (signal->isBaseLineInitialized()) { // fix the baseline to make it faster and more reliable
352 f->FixParameter(0, baselineEstimate);
353 } //*/
354 // Amplitude
355 f->SetParameter(1, amplEstimate / 0.0498); // 0.0498=e^{-3}
356 f->SetParLimits(1, 0,
357 maxValue / 0.0498 * 100); // max allowed amplitude is 100 times the saturation value
358 // Width or shaping time
359 f->SetParameter(2, widthEstimate);
360 f->SetParLimits(2, 0,
361 signal->GetNumberOfPoints()); // width should be positive and less than the window
362 // Peak position
363 f->SetParameter(3, peakposEstimate - widthEstimate);
364 f->SetParLimits(
365 3, 0, signal->GetNumberOfPoints()); // peak position should be positive and less than the window
366
367 std::string fitOptions = "R";
369 fitOptions += "NQ";
370 }
371 g->Fit(f, fitOptions.c_str());
372
374 g->Draw("AL");
375 }
376 // Add the recovered signal to the original signal
377 TRestRawSignal toAddSignal(0);
378 bool anyBinRecovered = false;
379 for (size_t i = 0; i < (size_t)signal->GetNumberOfPoints(); i++) {
380 if (std::find(saturatedBins.begin(), saturatedBins.end(), i) != saturatedBins.end()) {
381 Double_t value = f->Eval(i) - maxValue;
382 if (value > 0 || fProcessAllSignals) {
383 toAddSignal.AddPoint(value);
384 anyBinRecovered = true;
385 addedIntegral += value;
386 if (value > signalAddedAmplitude) signalAddedAmplitude = value;
387 RESTExtreme << " Adding value " << value << RESTendl;
388 continue;
389 }
390 }
391 toAddSignal.AddPoint((Short_t)0);
392 }
393
395 f->Draw("same");
396 fC->Update();
397 std::cin.get();
398 }
399
400 delete g;
401 delete f;
402
403 if (!anyBinRecovered) {
404 RESTDebug << " Signal " << s << " in event " << eventID << " not recovered" << RESTendl;
405 continue; // nothing to add
406 }
407 nSignalsRecovered++;
408 addedAmplitude += signalAddedAmplitude;
409 signal->SignalAddition(toAddSignal);
410 RESTDebug << " Signal " << s << " in event " << eventID << " recovered" << RESTendl;
411 }
412
413 SetObservableValue("AddedAmplitude", addedAmplitude);
414 SetObservableValue("AddedIntegral", addedIntegral);
415 SetObservableValue("SignalsSaturated", nSignalsSaturated);
416 SetObservableValue("SignalsRecovered", nSignalsRecovered);
417
418 return fAnaEvent;
419}
420
426 // Write here the jobs to do when all the events are processed
427}
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
endl_t RESTendl
Termination flag object for TRestStringOutput.
void SetLibraryVersion(TString version)
Set the library version of this metadata class.
TRestStringOutput::REST_Verbose_Level GetVerboseLevel()
returns the verboselevel in type of REST_Verbose_Level enumerator
void SetSectionName(std::string sName)
set the section name, clear the section content
An event container for time rawdata signals with fixed length.
void SetBaseLineRange(TVector2 blRange, std::string option="")
This class recovers the saturated signals in a TRestRawSignalEvent using a fit to the AGET pulse.
TVector2 fBaseLineRange
Range of bins to calculate the baseline and fix that parameter in the fit.
void Initialize() override
Function to initialize input/output event members and define the section name.
TRestRawSignalEvent * fAnaEvent
A pointer to the specific TRestRawSignalEvent input event.
void EndProcess() override
Function to include required actions after all events have been processed.
Size_t fMinSaturatedBins
Minimum number of saturated bins to consider a signal as saturated.
void InitProcess() override
Process initialization. Observable names can be re-interpreted here. Any action in the process requir...
TVector3 fInitPointsOverThreshold
Wrapper of (pointThreshold, signalThreshold, pointsOverThreshold) params.
TVector2 fFitRange
Range of bins to fit the signal.
Short_t fMinSaturationValue
Minimum value to consider a signal as saturated.
Bool_t fProcessAllSignals
Process all signals in the event.
TRestEvent * ProcessEvent(TRestEvent *eventInput) override
The main processing event function.
Size_t fNBinsIfNotSaturated
Number of bins to consider if the signal is not saturated.
It defines a Short_t array with a physical parameter that evolves in time using a fixed time bin.
std::vector< Int_t > GetPointsOverThreshold() const
Returns a std::vector containing the indexes of data points over threshold.
Double_t GetBaseLine() const
void InitializePointsOverThreshold(const TVector2 &thrPar, Int_t nPointsOver, Int_t nPointsFlat=512)
It initializes the fPointsOverThreshold array with the indexes of data points that are found over thr...
void SignalAddition(const TRestRawSignal &signal)
This method adds the signal provided by argument to the existing signal.
Double_t GetRawData(Int_t n) const
It returns the original data value of point n without baseline correction.
void AddPoint(Short_t)
Adds a new point to the end of the signal data array.
Bool_t IsADCSaturation(int Nflat=3)
It returns whether the signal has ADC saturation.
Int_t GetMaxPeakBin()
It returns the bin at which the maximum peak amplitude happens.
Int_t GetNumberOfPoints() const
Returns the actual number of points, or size of the signal.
Bool_t isBaseLineInitialized() const
Returns false if the baseline and its baseline fluctuation was not initialized.
@ REST_Debug
+show the defined debug messages