136 #include "TRestDetectorSignalToRawSignalProcess.h"
138 #include <TObjString.h>
139 #include <TRestRawReadoutMetadata.h>
166 LoadConfig(configFilename);
173 delete fOutputRawSignalEvent;
189 LoadConfigFromFile(configFilename, name);
197 SetSectionName(this->ClassName());
198 SetLibraryVersion(LIBRARY_VERSION);
200 fInputSignalEvent =
nullptr;
210 if (fInputSignalEvent->GetNumberOfSignals() <= 0) {
218 fOutputRawSignalEvent->SetID(fInputSignalEvent->GetID());
219 fOutputRawSignalEvent->SetSubID(fInputSignalEvent->GetSubID());
220 fOutputRawSignalEvent->SetTimeStamp(fInputSignalEvent->GetTimeStamp());
221 fOutputRawSignalEvent->SetSubEventTag(fInputSignalEvent->GetSubEventTag());
223 double startTimeNoOffset = 0;
225 if (fTriggerMode ==
"firstDeposit") {
226 startTimeNoOffset = fInputSignalEvent->GetMinTime();
227 }
else if (fTriggerMode ==
"integralThreshold") {
228 bool thresholdReached =
false;
229 for (Double_t t = fInputSignalEvent->GetMinTime() - fNPoints * fSampling;
230 t <= fInputSignalEvent->GetMaxTime() + fNPoints * fSampling; t = t + 0.5) {
231 Double_t energy = fInputSignalEvent->GetIntegralWithTime(t, t + (fSampling * fNPoints) / 2.);
233 if (energy > fIntegralThreshold) {
234 startTimeNoOffset = t;
235 thresholdReached =
true;
238 if (!thresholdReached) {
239 RESTWarning <<
"Integral threshold for trigger not reached" << RESTendl;
240 startTimeNoOffset = 0;
242 }
else if (fTriggerMode ==
"observable") {
243 const auto obs = GetObservableValue<double>(fTriggerModeObservableName);
244 startTimeNoOffset = obs;
246 }
else if (fTriggerMode ==
"firstDepositTPC" || fTriggerMode ==
"integralThresholdTPC") {
247 fReadout = GetMetadata<TRestDetectorReadout>();
249 if (fReadout ==
nullptr) {
250 RESTError <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
251 <<
"TRestDetectorReadout metadata not found" << RESTendl;
255 set<const TRestDetectorSignal*> tpcSignals;
257 for (
int n = 0; n < fInputSignalEvent->GetNumberOfSignals(); n++) {
259 if (signal->GetSignalType() ==
"tpc") {
260 tpcSignals.insert(signal);
271 if (tpcSignals.empty()) {
275 if (fTriggerMode ==
"firstDepositTPC") {
276 double startTime = std::numeric_limits<float>::max();
277 for (
const auto& signal : tpcSignals) {
278 const auto minTime = signal->GetMinTime();
279 if (minTime < startTime) {
284 if (startTime >= std::numeric_limits<float>::max()) {
287 startTimeNoOffset = startTime;
289 }
else if (fTriggerMode ==
"integralThresholdTPC") {
290 RESTDebug <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
291 <<
"Trigger mode integralThresholdTPC" << RESTendl;
293 const double signalIntegralThreshold = 0.5;
294 double totalEnergy = 0;
295 for (
const auto& signal : tpcSignals) {
296 totalEnergy += signal->GetIntegral();
298 if (totalEnergy < signalIntegralThreshold) {
303 double minTime = std::numeric_limits<float>::max();
304 for (
const auto& signal : tpcSignals) {
305 const auto maxSignalTime = signal->GetMaxTime();
306 if (maxSignalTime > maxTime) {
307 maxTime = maxSignalTime;
309 const auto minSignalTime = signal->GetMinTime();
310 if (minSignalTime < minTime) {
311 minTime = minSignalTime;
316 if (minTime > maxTime) {
318 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
319 <<
"minTime > maxTime" << RESTendl;
325 <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: " << inputEvent->GetID()
326 <<
" signal minTime < 0. Setting min time to 0, but this should probably never happen"
334 bool thresholdReached =
false;
335 double maxEnergy = 0;
336 while (t < maxTime) {
339 for (
const auto& signal : tpcSignals) {
340 energy += signal->GetIntegralWithTime(t - fSampling * fNPoints, t);
342 if (energy > maxEnergy) {
345 if (maxEnergy > signalIntegralThreshold) {
346 thresholdReached =
true;
352 if (!thresholdReached) {
361 double startTime = t;
362 startTimeNoOffset = startTime;
364 SetObservableValue(
"triggerTimeTPC", startTime);
367 }
else if (fTriggerMode ==
"fixed") {
368 startTimeNoOffset = fTriggerFixedStartTime;
370 cerr <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
371 <<
"Trigger mode not recognized" << RESTendl;
375 for (
int n = 0; n < fInputSignalEvent->GetNumberOfSignals(); n++) {
377 Int_t signalID = signal->GetSignalID();
378 string type = signal->GetSignalType();
380 if (fParametersMap.find(type) == fParametersMap.end()) {
381 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
382 <<
"type " << type <<
" not found in parameters map" << RESTendl;
386 double sampling = fParametersMap.at(type).sampling;
387 double shapingTime = fParametersMap.at(type).shapingTime;
388 double calibrationGain = fParametersMap.at(type).calibrationGain;
389 double calibrationOffset = fParametersMap.at(type).calibrationOffset;
391 double timeStart = startTimeNoOffset - fTriggerDelay * sampling;
392 double timeEnd = timeStart + fNPoints * sampling;
393 RESTDebug <<
"fTimeStart: " << timeStart <<
" us " << RESTendl;
394 RESTDebug <<
"fTimeEnd: " << timeEnd <<
" us " << RESTendl;
396 if (timeStart + fTriggerDelay * sampling < 0) {
398 cerr <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
399 <<
"fTimeStart < - fTriggerDelay * fSampling" << endl;
406 if (timeStart + fTriggerDelay * fSampling < 0) {
408 RESTError <<
"TRestDetectorSignalToRawSignalProcess::ProcessEvent: "
409 <<
"fTimeStart < - fTriggerDelay * fSampling" << RESTendl;
413 vector<Double_t> data(fNPoints, calibrationOffset);
415 for (
int m = 0; m < signal->GetNumberOfPoints(); m++) {
416 Double_t t = signal->GetTime(m);
417 Double_t d = signal->GetData(m);
420 cout <<
"Signal: " << n <<
" Sample: " << m <<
" T: " << t <<
" Data: " << d << endl;
423 if (t > timeStart && t < timeEnd) {
425 Int_t timeBin = (Int_t)round((t - timeStart) / sampling);
427 if (GetVerboseLevel() >= TRestStringOutput::REST_Verbose_Level::REST_Warning) {
428 if (timeBin < 0 || timeBin > fNPoints) {
429 cout <<
"Time bin out of range!!! bin value: " << timeBin << endl;
434 RESTDebug <<
"Adding data: " << signal->GetData(m) <<
" to Time Bin: " << timeBin << RESTendl;
435 data[timeBin] += calibrationGain * signal->GetData(m);
439 if (shapingTime > 0) {
440 const auto sinShaper = [](Double_t t) -> Double_t {
446 return TMath::Exp(-3.0 * t) * TMath::Power(t, 3.0) * TMath::Sin(t) * 22.68112123672292;
449 const auto shapingFunction = [&sinShaper](Double_t t) -> Double_t {
459 vector<Double_t> dataAfterShaping(fNPoints, calibrationOffset);
460 for (
int i = 0; i < fNPoints; i++) {
461 const Double_t value = data[i] - calibrationOffset;
466 for (
int j = 0; j < fNPoints; j++) {
467 dataAfterShaping[j] += value * shapingFunction(((j - i) * sampling) / shapingTime);
470 data = dataAfterShaping;
475 for (
int x = 0; x < fNPoints; x++) {
476 double value = round(data[x]);
477 if (GetVerboseLevel() >= TRestStringOutput::REST_Verbose_Level::REST_Warning) {
478 if (value < numeric_limits<Short_t>::min() || value > numeric_limits<Short_t>::max()) {
479 RESTDebug <<
"value (" << value <<
") is outside short range ("
480 << numeric_limits<Short_t>::min() <<
", " << numeric_limits<Short_t>::max()
485 if (value < numeric_limits<Short_t>::min()) {
486 value = numeric_limits<Short_t>::min();
487 fOutputRawSignalEvent->SetOK(
false);
488 }
else if (value > numeric_limits<Short_t>::max()) {
489 value = numeric_limits<Short_t>::max();
490 fOutputRawSignalEvent->SetOK(
false);
498 RESTDebug <<
"Adding signal to raw signal event" << RESTendl;
500 fOutputRawSignalEvent->AddSignal(rawSignal);
503 RESTDebug <<
"TRestDetectorSignalToRawSignalProcess. Returning event with N signals "
504 << fOutputRawSignalEvent->GetNumberOfSignals() << RESTendl;
506 return fOutputRawSignalEvent;
514 TString readoutTypesString = GetParameter(
"readoutTypes",
"");
516 TObjArray* readoutTypesArray = readoutTypesString.Tokenize(
",");
517 for (
int i = 0; i < readoutTypesArray->GetEntries(); i++) {
518 fReadoutTypes.insert(((TObjString*)readoutTypesArray->At(i))->GetString().Data());
520 cout <<
"readout types: ";
521 for (
const auto& type : fReadoutTypes) {
527 const string defaultType;
528 fReadoutTypes.insert(defaultType);
529 fParametersMap[defaultType] = {};
531 for (
const auto& type : fReadoutTypes) {
532 fReadoutTypes.insert(type);
533 fParametersMap[type] = {};
535 string typeCamelCase = type;
536 typeCamelCase[0] = toupper(typeCamelCase[0]);
539 parameters.sampling = GetDblParameterWithUnits(
"sampling" + typeCamelCase, parameters.sampling);
540 parameters.shapingTime =
541 GetDblParameterWithUnits(
"shapingTime" + typeCamelCase, parameters.shapingTime);
542 parameters.calibrationGain =
543 GetDblParameterWithUnits(
"gain" + typeCamelCase, parameters.calibrationGain);
544 parameters.calibrationOffset =
545 GetDblParameterWithUnits(
"offset" + typeCamelCase, parameters.calibrationOffset);
546 parameters.calibrationEnergy =
547 Get2DVectorParameterWithUnits(
"calibrationEnergy" + typeCamelCase, parameters.calibrationEnergy);
548 parameters.calibrationRange =
549 Get2DVectorParameterWithUnits(
"calibrationRange" + typeCamelCase, parameters.calibrationRange);
551 const bool isLinearCalibration =
552 (parameters.calibrationEnergy.Mod() != 0 && parameters.calibrationRange.Mod() != 0);
554 if (isLinearCalibration) {
555 const auto range = numeric_limits<Short_t>::max() - numeric_limits<Short_t>::min();
556 parameters.calibrationGain =
557 range * (parameters.calibrationRange.Y() - parameters.calibrationRange.X()) /
558 (parameters.calibrationEnergy.Y() - parameters.calibrationEnergy.X());
559 parameters.calibrationOffset =
560 range * (parameters.calibrationRange.X() -
561 parameters.calibrationGain * parameters.calibrationEnergy.X()) +
562 numeric_limits<Short_t>::min();
564 fParametersMap[type] = parameters;
567 auto nPoints = GetParameter(
"nPoints");
568 if (nPoints == PARAMETER_NOT_FOUND_STR) {
569 nPoints = GetParameter(
"Npoints", fNPoints);
573 fTriggerMode = GetParameter(
"triggerMode", fTriggerMode);
574 const set<string> validTriggerModes = {
"firstDeposit",
"integralThreshold",
"fixed",
575 "observable",
"firstDepositTPC",
"integralThresholdTPC"};
576 if (validTriggerModes.count(fTriggerMode) == 0) {
577 RESTError <<
"Trigger mode set to: '" << fTriggerMode
578 <<
"' which is not a valid trigger mode. Please use one of the following trigger modes: ";
579 for (
const auto& triggerMode : validTriggerModes) {
580 RESTError << triggerMode <<
" ";
582 RESTError << RESTendl;
586 fTriggerDelay =
StringToInteger(GetParameter(
"triggerDelay", fTriggerDelay));
587 fIntegralThreshold =
StringToDouble(GetParameter(
"integralThreshold", fIntegralThreshold));
588 fTriggerFixedStartTime = GetDblParameterWithUnits(
"triggerFixedStartTime", fTriggerFixedStartTime);
591 fSampling = fParametersMap.at(defaultType).sampling;
592 fShapingTime = fParametersMap.at(defaultType).shapingTime;
593 fCalibrationGain = fParametersMap.at(defaultType).calibrationGain;
594 fCalibrationOffset = fParametersMap.at(defaultType).calibrationOffset;
595 fCalibrationEnergy = fParametersMap.at(defaultType).calibrationEnergy;
596 fCalibrationRange = fParametersMap.at(defaultType).calibrationRange;
598 if (fTriggerMode ==
"observable") {
599 fTriggerModeObservableName = GetParameter(
"triggerModeObservableName",
"");
600 if (fTriggerModeObservableName.empty()) {
601 RESTError <<
"You need to set 'triggerModeObservableName' to a valid analysis tree observable"
610 Double_t TRestDetectorSignalToRawSignalProcess::GetEnergyFromADC(Double_t adc,
const string& type)
const {
611 if (fParametersMap.find(type) == fParametersMap.end()) {
612 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::GetEnergyFromADC: "
613 <<
"type " << type <<
" not found in parameters map" << RESTendl;
616 const auto gain = fParametersMap.at(type).calibrationGain;
617 const auto offset = fParametersMap.at(type).calibrationOffset;
618 return (adc - offset) / gain;
621 Double_t TRestDetectorSignalToRawSignalProcess::GetADCFromEnergy(Double_t energy,
const string& type)
const {
622 if (fParametersMap.find(type) == fParametersMap.end()) {
623 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::GetEnergyFromADC: "
624 <<
"type " << type <<
" not found in parameters map" << RESTendl;
627 const auto gain = fParametersMap.at(type).calibrationGain;
628 const auto offset = fParametersMap.at(type).calibrationOffset;
629 return energy * gain + offset;
632 Double_t TRestDetectorSignalToRawSignalProcess::GetTimeFromBin(Double_t bin,
const string& type)
const {
633 if (fParametersMap.find(type) == fParametersMap.end()) {
634 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::GetEnergyFromADC: "
635 <<
"type " << type <<
" not found in parameters map" << RESTendl;
638 const auto sampling = fParametersMap.at(type).sampling;
639 return (bin - fTriggerDelay) * sampling;
642 Double_t TRestDetectorSignalToRawSignalProcess::GetBinFromTime(Double_t time,
const string& type)
const {
643 if (fParametersMap.find(type) == fParametersMap.end()) {
644 RESTWarning <<
"TRestDetectorSignalToRawSignalProcess::GetEnergyFromADC: "
645 <<
"type " << type <<
" not found in parameters map" << RESTendl;
648 const auto sampling = fParametersMap.at(type).sampling;
649 return (UShort_t)((time + fTriggerDelay * sampling) / sampling);
655 RESTMetadata <<
"Points per channel: " << fNPoints << RESTendl;
656 RESTMetadata <<
"Trigger mode: " << fTriggerMode << RESTendl;
657 RESTMetadata <<
"Trigger delay: " << fTriggerDelay <<
" units" << RESTendl;
659 for (
const auto& readoutType : fReadoutTypes) {
660 RESTMetadata << RESTendl;
661 string type = readoutType;
665 RESTMetadata <<
"Readout type: " << type << RESTendl;
666 RESTMetadata <<
"Sampling time: " << fParametersMap.at(readoutType).sampling * 1000 <<
" ns"
668 const double shapingTime = fParametersMap.at(readoutType).shapingTime;
669 if (shapingTime > 0) {
670 RESTMetadata <<
"Shaping time: " << shapingTime * 1000 <<
" ns" << RESTendl;
673 if (IsLinearCalibration()) {
674 RESTMetadata <<
"Calibration energies: (" << fParametersMap.at(readoutType).calibrationEnergy.X()
675 <<
", " << fParametersMap.at(readoutType).calibrationEnergy.Y() <<
") keV"
677 RESTMetadata <<
"Calibration range: (" << fParametersMap.at(readoutType).calibrationRange.X()
678 <<
", " << fParametersMap.at(readoutType).calibrationRange.Y() <<
")" << RESTendl;
680 RESTMetadata <<
"ADC Gain: " << fParametersMap.at(readoutType).calibrationGain << RESTendl;
681 RESTMetadata <<
"ADC Offset: " << fParametersMap.at(readoutType).calibrationOffset << RESTendl;
A process to convert a TRestDetectorSignalEvent into a TRestRawSignalEvent.
TRestEvent * ProcessEvent(TRestEvent *inputEvent) override
The main processing event function.
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)
void PrintMetadata() override
It prints out the process parameters stored in the metadata structure.
TRestDetectorSignalToRawSignalProcess()
Default constructor.
~TRestDetectorSignalToRawSignalProcess()
Default destructor.
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...
A base class for any REST event.
virtual void PrintEvent() const
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.