136#include "TRestDetectorSignalToRawSignalProcess.h"
138#include <TObjString.h>
139#include <TRestRawReadoutMetadata.h>
223 double triggerTime = 0;
224 double startTimeNoOffset = 0;
229 bool thresholdReached =
false;
235 startTimeNoOffset = t;
236 thresholdReached =
true;
239 if (!thresholdReached) {
240 RESTWarning <<
"Integral threshold for trigger not reached" <<
RESTendl;
241 startTimeNoOffset = 0;
245 startTimeNoOffset = obs;
248 fReadout = GetMetadata<TRestDetectorReadout>();
250 if (fReadout ==
nullptr) {
251 RESTError <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
252 <<
"TRestDetectorReadout metadata not found" <<
RESTendl;
256 set<const TRestDetectorSignal*> tpcSignals;
260 if (signal->GetSignalType() ==
"tpc") {
261 tpcSignals.insert(signal);
272 if (tpcSignals.empty()) {
277 double startTime = std::numeric_limits<float>::max();
278 for (
const auto& signal : tpcSignals) {
279 const auto minTime = signal->GetMinTime();
280 if (minTime < startTime) {
285 if (startTime >= std::numeric_limits<float>::max()) {
288 startTimeNoOffset = startTime;
291 RESTDebug <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
292 <<
"Trigger mode integralThresholdTPC" <<
RESTendl;
294 if (fIntegralThresholdTPCkeV <= 0) {
295 RESTError <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
296 <<
"integralThresholdTPCkeV must be greater than 0: " << fIntegralThresholdTPCkeV
301 double totalEnergy = 0;
302 for (
const auto& signal : tpcSignals) {
303 totalEnergy += signal->GetIntegral();
305 if (totalEnergy < fIntegralThresholdTPCkeV) {
309 Double_t maxTime = std::numeric_limits<Double_t>::min();
310 Double_t minTime = std::numeric_limits<Double_t>::max();
311 for (
const auto& signal : tpcSignals) {
312 const auto maxSignalTime = signal->GetMaxTime();
313 if (maxSignalTime > maxTime) {
314 maxTime = maxSignalTime;
316 const auto minSignalTime = signal->GetMinTime();
317 if (minSignalTime < minTime) {
318 minTime = minSignalTime;
321 if (minSignalTime < 0) {
322 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: EventID: "
324 <<
" minSignalTime < 0. MinSignalTime: " << minSignalTime <<
RESTendl;
330 if (minTime > maxTime || minTime < 0) {
331 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: EventID: "
333 <<
" minTime > maxTime or minTime < 0. MinTime: " << minTime
334 <<
" MaxTime: " << maxTime <<
RESTendl;
338 triggerTime = minTime;
339 bool thresholdReached =
false;
340 double maxEnergy = 0;
341 while (triggerTime <= maxTime +
fSampling) {
345 for (
const auto& signal : tpcSignals) {
346 energy += signal->GetIntegralWithTime(startTime, triggerTime);
348 if (energy > maxEnergy) {
351 if (maxEnergy >= fIntegralThresholdTPCkeV) {
352 thresholdReached =
true;
358 if (!thresholdReached) {
362 startTimeNoOffset = triggerTime;
368 cerr <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
369 <<
"Trigger mode not recognized" <<
RESTendl;
375 Int_t signalID = signal->GetSignalID();
376 string type = signal->GetSignalType();
378 if (fParametersMap.find(type) == fParametersMap.end()) {
379 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
380 <<
"type " << type <<
" not found in parameters map" <<
RESTendl;
384 double noiseLevel = fParametersMap.at(type).noiseLevel;
385 double sampling = fParametersMap.at(type).sampling;
386 double shapingTime = fParametersMap.at(type).shapingTime;
387 double calibrationGain = fParametersMap.at(type).calibrationGain;
388 double calibrationOffset = fParametersMap.at(type).calibrationOffset;
390 double timeStart = startTimeNoOffset -
fTriggerDelay * sampling;
391 double timeEnd = timeStart +
fNPoints * sampling;
392 RESTDebug <<
"fTimeStart: " << timeStart <<
" us " <<
RESTendl;
393 RESTDebug <<
"fTimeEnd: " << timeEnd <<
" us " <<
RESTendl;
397 cerr <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
398 <<
"fTimeStart < - fTriggerDelay * fSampling" << endl;
407 RESTError <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
408 <<
"fTimeStart < - fTriggerDelay * fSampling" <<
RESTendl;
412 vector<Double_t> data(
fNPoints, calibrationOffset);
414 for (
int m = 0; m < signal->GetNumberOfPoints(); m++) {
415 Double_t t = signal->GetTime(m);
416 Double_t d = signal->GetData(m);
419 cout <<
"Signal: " << n <<
" Sample: " << m <<
" T: " << t <<
" Data: " << d << endl;
422 if (t > timeStart && t < timeEnd) {
424 auto timeBin = (Int_t)round((t - timeStart) / sampling);
426 if (
GetVerboseLevel() >= TRestStringOutput::REST_Verbose_Level::REST_Warning) {
427 if (timeBin < 0 || timeBin >
fNPoints) {
428 cout <<
"Time bin out of range!!! bin value: " << timeBin << endl;
433 RESTDebug <<
"Adding data: " << signal->GetData(m) <<
" to Time Bin: " << timeBin <<
RESTendl;
434 data[timeBin] += calibrationGain * signal->GetData(m);
439 if (noiseLevel > 0) {
440 for (
int i = 0; i <
fNPoints; i++) {
441 data[i] += gRandom->Gaus(0, noiseLevel);
445 if (shapingTime > 0) {
446 const auto sinShaper = [](Double_t t) -> Double_t {
452 return TMath::Exp(-3.0 * t) * TMath::Power(t, 3.0) * TMath::Sin(t) * 22.68112123672292;
455 const auto shapingFunction = [&sinShaper](Double_t t) -> Double_t {
465 vector<Double_t> dataAfterShaping(
fNPoints, calibrationOffset);
466 for (
int i = 0; i <
fNPoints; i++) {
467 const Double_t value = data[i] - calibrationOffset;
472 for (
int j = 0; j <
fNPoints; j++) {
473 dataAfterShaping[j] += value * shapingFunction(((j - i) * sampling) / shapingTime);
476 data = dataAfterShaping;
479 if (noiseLevel > 0) {
480 for (
int i = 0; i <
fNPoints; i++) {
481 data[i] += gRandom->Gaus(0, noiseLevel);
488 for (
int x = 0; x <
fNPoints; x++) {
489 double value = round(data[x]);
490 if (
GetVerboseLevel() >= TRestStringOutput::REST_Verbose_Level::REST_Warning) {
491 if (value < numeric_limits<Short_t>::min() || value > numeric_limits<Short_t>::max()) {
492 RESTDebug <<
"value (" << value <<
") is outside short range ("
493 << numeric_limits<Short_t>::min() <<
", " << numeric_limits<Short_t>::max()
498 if (value < numeric_limits<Short_t>::min()) {
499 value = numeric_limits<Short_t>::min();
501 }
else if (value > numeric_limits<Short_t>::max()) {
502 value = numeric_limits<Short_t>::max();
511 RESTDebug <<
"Adding signal to raw signal event" <<
RESTendl;
518 RESTDebug <<
"TRestDetectorSignalToRawSignalProcess. Returning event with N signals "
529 TString readoutTypesString =
GetParameter(
"readoutTypes",
"");
531 TObjArray* readoutTypesArray = readoutTypesString.Tokenize(
",");
532 for (
int i = 0; i < readoutTypesArray->GetEntries(); i++) {
533 fReadoutTypes.insert(((TObjString*)readoutTypesArray->At(i))->GetString().Data());
535 cout <<
"readout types: ";
536 for (
const auto& type : fReadoutTypes) {
542 const string defaultType;
543 fReadoutTypes.insert(defaultType);
544 fParametersMap[defaultType] = {};
546 for (
const auto& type : fReadoutTypes) {
547 fReadoutTypes.insert(type);
548 fParametersMap[type] = {};
550 string typeCamelCase = type;
551 typeCamelCase[0] = toupper(typeCamelCase[0]);
554 parameters.sampling = GetDblParameterWithUnits(
"sampling" + typeCamelCase, parameters.sampling);
555 parameters.shapingTime =
556 GetDblParameterWithUnits(
"shapingTime" + typeCamelCase, parameters.shapingTime);
557 parameters.calibrationGain =
558 GetDblParameterWithUnits(
"gain" + typeCamelCase, parameters.calibrationGain);
559 parameters.calibrationOffset =
560 GetDblParameterWithUnits(
"offset" + typeCamelCase, parameters.calibrationOffset);
561 parameters.calibrationEnergy =
562 Get2DVectorParameterWithUnits(
"calibrationEnergy" + typeCamelCase, parameters.calibrationEnergy);
563 parameters.calibrationRange =
564 Get2DVectorParameterWithUnits(
"calibrationRange" + typeCamelCase, parameters.calibrationRange);
565 parameters.noiseLevel = GetDblParameterWithUnits(
"noiseLevel" + typeCamelCase, parameters.noiseLevel);
567 const bool isLinearCalibration =
568 (parameters.calibrationEnergy.Mod() != 0 && parameters.calibrationRange.Mod() != 0);
570 if (isLinearCalibration) {
571 const auto range = numeric_limits<Short_t>::max() - numeric_limits<Short_t>::min();
572 parameters.calibrationGain =
573 range * (parameters.calibrationRange.Y() - parameters.calibrationRange.X()) /
574 (parameters.calibrationEnergy.Y() - parameters.calibrationEnergy.X());
575 parameters.calibrationOffset =
576 range * (parameters.calibrationRange.X() -
577 parameters.calibrationGain * parameters.calibrationEnergy.X()) +
578 numeric_limits<Short_t>::min();
580 fParametersMap[type] = parameters;
584 if (nPoints == PARAMETER_NOT_FOUND_STR) {
590 const set<string> validTriggerModes = {
"firstDeposit",
"integralThreshold",
"fixed",
591 "observable",
"firstDepositTPC",
"integralThresholdTPC"};
594 <<
"' which is not a valid trigger mode. Please use one of the following trigger modes: ";
595 for (
const auto& triggerMode : validTriggerModes) {
596 RESTError << triggerMode <<
" ";
604 fIntegralThresholdTPCkeV =
606 if (fIntegralThresholdTPCkeV <= 0) {
607 RESTWarning <<
"integralThresholdTPCkeV must be greater than 0: " << fIntegralThresholdTPCkeV
616 fSampling = fParametersMap.at(defaultType).sampling;
617 fShapingTime = fParametersMap.at(defaultType).shapingTime;
618 fNoiseLevel = fParametersMap.at(defaultType).noiseLevel;
620 fCalibrationOffset = fParametersMap.at(defaultType).calibrationOffset;
627 RESTError <<
"You need to set 'triggerModeObservableName' to a valid analysis tree observable"
636Double_t TRestDetectorSignalToRawSignalProcess::GetEnergyFromADC(Double_t adc,
const string& type)
const {
637 if (fParametersMap.find(type) == fParametersMap.end()) {
638 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::GetEnergyFromADC: "
639 <<
"type " << type <<
" not found in parameters map" <<
RESTendl;
642 const auto gain = fParametersMap.at(type).calibrationGain;
643 const auto offset = fParametersMap.at(type).calibrationOffset;
644 return (adc - offset) / gain;
647Double_t TRestDetectorSignalToRawSignalProcess::GetADCFromEnergy(Double_t energy,
const string& type)
const {
648 if (fParametersMap.find(type) == fParametersMap.end()) {
649 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::GetEnergyFromADC: "
650 <<
"type " << type <<
" not found in parameters map" <<
RESTendl;
653 const auto gain = fParametersMap.at(type).calibrationGain;
654 const auto offset = fParametersMap.at(type).calibrationOffset;
655 return energy * gain + offset;
658Double_t TRestDetectorSignalToRawSignalProcess::GetTimeFromBin(Double_t bin,
const string& type)
const {
659 if (fParametersMap.find(type) == fParametersMap.end()) {
660 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::GetEnergyFromADC: "
661 <<
"type " << type <<
" not found in parameters map" <<
RESTendl;
664 const auto sampling = fParametersMap.at(type).sampling;
668Double_t TRestDetectorSignalToRawSignalProcess::GetBinFromTime(Double_t time,
const string& type)
const {
669 if (fParametersMap.find(type) == fParametersMap.end()) {
670 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::GetEnergyFromADC: "
671 <<
"type " << type <<
" not found in parameters map" <<
RESTendl;
674 const auto sampling = fParametersMap.at(type).sampling;
675 return (UShort_t)((time +
fTriggerDelay * sampling) / sampling);
685 for (
const auto& readoutType : fReadoutTypes) {
687 string type = readoutType;
691 RESTMetadata <<
"Readout type: " << type <<
RESTendl;
692 RESTMetadata <<
"Sampling time: " << fParametersMap.at(readoutType).sampling * 1000 <<
" ns"
694 const double shapingTime = fParametersMap.at(readoutType).shapingTime;
695 if (shapingTime > 0) {
696 RESTMetadata <<
"Shaping time: " << shapingTime * 1000 <<
" ns" <<
RESTendl;
698 const double noiseLevel = fParametersMap.at(readoutType).noiseLevel;
699 if (noiseLevel > 0) {
700 RESTMetadata <<
"Noise Level: " << noiseLevel <<
RESTendl;
703 if (IsLinearCalibration()) {
704 RESTMetadata <<
"Calibration energies: (" << fParametersMap.at(readoutType).calibrationEnergy.X()
705 <<
", " << fParametersMap.at(readoutType).calibrationEnergy.Y() <<
") keV"
707 RESTMetadata <<
"Calibration range: (" << fParametersMap.at(readoutType).calibrationRange.X()
708 <<
", " << fParametersMap.at(readoutType).calibrationRange.Y() <<
")" <<
RESTendl;
710 RESTMetadata <<
"ADC Gain: " << fParametersMap.at(readoutType).calibrationGain <<
RESTendl;
711 RESTMetadata <<
"ADC Offset: " << fParametersMap.at(readoutType).calibrationOffset <<
RESTendl;
A process to convert a TRestDetectorSignalEvent into a TRestRawSignalEvent.
TVector2 fCalibrationEnergy
two distinct energy values used for calibration
TRestDetectorSignalEvent * fInputSignalEvent
A pointer to the specific TRestDetectorSignalEvent input.
TRestEvent * ProcessEvent(TRestEvent *inputEvent) override
The main processing event function.
Double_t fSampling
The sampling time from the binned raw output signal.
void Initialize() override
Function to initialize input/output event members and define the section name.
void InitProcess() override
To be executed at the beginning of the run (outside event loop)
TRestRawSignalEvent * fOutputRawSignalEvent
A pointer to the specific TRestRawSignalEvent input.
std::string fTriggerMode
It is used to define the way the time start will be fixed.
void PrintMetadata() override
It prints out the process parameters stored in the metadata structure.
TVector2 fCalibrationRange
position in the range corresponding to the energy in 'fCalibrationEnergy'. Values between 0 and 1
~TRestDetectorSignalToRawSignalProcess() override
Default destructor.
Double_t fIntegralThreshold
This parameter is used by integralWindow trigger mode to define the acquisition window.
Int_t fNPoints
The number of points of the resulting output signal.
TRestDetectorSignalToRawSignalProcess()
Default constructor.
std::string fTriggerModeObservableName
The name of the observable used to define the trigger mode (i.e. g4Ana_sensitiveVolumeFirstHitTime)
Int_t fTriggerFixedStartTime
The starting time for the "fixed" trigger mode (can be offset by the trigger delay)
Double_t fCalibrationGain
Int_t fTriggerDelay
The number of time bins the time start is delayed in the resulting output signal.
void LoadConfig(const std::string &configFilename, const std::string &name="")
Function to load the configuration from an external configuration file.
void InitFromConfigFile() override
Function reading input parameters from the RML TRestDetectorSignalToRawSignalProcess metadata section...
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.
An event container for time rawdata signals with fixed length.
It defines a Short_t array with a physical parameter that evolves in time using a fixed time bin.
void Print() const
It prints the signal data on screen.
void SetSignalID(Int_t sID)
It sets the id number of the signal.
void AddPoint(Short_t)
Adds a new point to the end of the signal data array.
@ REST_Debug
+show the defined debug messages
Double_t StringToDouble(std::string in)
Gets a double from a string.
Int_t StringToInteger(std::string in)
Gets an integer from a string.