-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implementation of process to select events by their timeStamp
- Loading branch information
Showing
2 changed files
with
355 additions
and
0 deletions.
There are no files selected for viewing
84 changes: 84 additions & 0 deletions
84
source/framework/analysis/inc/TRestEventTimeSelectionProcess.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/************************************************************************* | ||
* This file is part of the REST software framework. * | ||
* * | ||
* Copyright (C) 2016 GIFNA/TREX (University of Zaragoza) * | ||
* For more information see http://gifna.unizar.es/trex * | ||
* * | ||
* REST is free software: you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation, either version 3 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
* REST is distributed in the hope that it will be useful, * | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
* GNU General Public License for more details. * | ||
* * | ||
* You should have a copy of the GNU General Public License along with * | ||
* REST in $REST_PATH/LICENSE. * | ||
* If not, see http://www.gnu.org/licenses/. * | ||
* For the list of contributors see $REST_PATH/CREDITS. * | ||
*************************************************************************/ | ||
|
||
#ifndef RestProcess_TRestEventTimeSelectionProcess | ||
#define RestProcess_TRestEventTimeSelectionProcess | ||
|
||
#include <TRestEventProcess.h> | ||
|
||
#include <iostream> | ||
|
||
|
||
class TRestEventTimeSelectionProcess : public TRestEventProcess { | ||
private: | ||
TRestEvent* fEvent; //! | ||
std::string fFileWithTimes; | ||
Bool_t fIsActiveTime; | ||
Char_t fDelimiter; | ||
Long_t fOffsetTimeInSeconds; | ||
std::vector<std::pair<std::string,std::string>> fStartEndTimes; | ||
|
||
/// Information about the events processed | ||
|
||
Int_t fNEventsRejected; | ||
Int_t fNEventsSelected; | ||
Double_t fTotalTimeInSeconds; | ||
|
||
void Initialize() override; | ||
|
||
protected: | ||
public: | ||
RESTValue GetInputEvent() const override { return fEvent; } | ||
RESTValue GetOutputEvent() const override { return fEvent; } | ||
|
||
void InitProcess() override; | ||
TRestEvent* ProcessEvent(TRestEvent* inputEvent) override; | ||
void EndProcess() override; | ||
|
||
void PrintMetadata() override; | ||
|
||
// Constructor | ||
TRestEventTimeSelectionProcess(); | ||
// Destructor | ||
~TRestEventTimeSelectionProcess() {} | ||
|
||
const char* GetProcessName() const override { return "EventTimeSelectionProcess"; } | ||
|
||
std::string GetFileWithTimes() const { return fFileWithTimes; } | ||
|
||
Bool_t GetIsActiveTime() const { return fIsActiveTime; } | ||
Char_t GetDelimiter() const { return fDelimiter; } | ||
|
||
std::vector<std::pair<std::string,std::string>> GetStartEndTimes() const { return fStartEndTimes; } | ||
std::string GetTimeStampCut(std::string timeStampObsName = "timeStamp", Bool_t useOffset = true, Int_t nTimes = -1); | ||
Int_t GetNEventsRejected() const { return fNEventsRejected; } | ||
Int_t GetNEventsSelected() const { return fNEventsSelected; } | ||
Double_t GetTotalTimeInSeconds() const { return fTotalTimeInSeconds; } | ||
|
||
void SetFileWithTimes(const std::string& fileWithTimes) { fFileWithTimes = fileWithTimes; } | ||
void SetIsActiveTime(Bool_t isActiveTime) { fIsActiveTime = isActiveTime; } | ||
void SetDelimiter(Char_t delimiter) { fDelimiter = delimiter; } | ||
void SetStartEndTimes(const std::vector<std::pair<std::string,std::string>>& startEndTimes) { fStartEndTimes = startEndTimes; } | ||
|
||
ClassDefOverride(TRestEventTimeSelectionProcess, 1); | ||
}; | ||
#endif |
271 changes: 271 additions & 0 deletions
271
source/framework/analysis/src/TRestEventTimeSelectionProcess.cxx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,271 @@ | ||
/************************************************************************* | ||
* This file is part of the REST software framework. * | ||
* * | ||
* Copyright (C) 2016 GIFNA/TREX (University of Zaragoza) * | ||
* For more information see http://gifna.unizar.es/trex * | ||
* * | ||
* REST is free software: you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation, either version 3 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
* REST is distributed in the hope that it will be useful, * | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
* GNU General Public License for more details. * | ||
* * | ||
* You should have a copy of the GNU General Public License along with * | ||
* REST in $REST_PATH/LICENSE. * | ||
* If not, see http://www.gnu.org/licenses/. * | ||
* For the list of contributors see $REST_PATH/CREDITS. * | ||
*************************************************************************/ | ||
|
||
////////////////////////////////////////////////////////////////////////// | ||
/// The TRestEventTimeSelectionProcess allows processing of events that are within | ||
/// a certain time range. The time ranges are read from a file that contains | ||
/// the start and end times of the periods. The file should have the following | ||
/// format (it can have more columns separated by the same delimiter, but the first | ||
/// two columns should be the start and end times and all the other columns | ||
/// will be ignored): | ||
/// \code | ||
/// # This is a comment | ||
/// # Start time,End time | ||
/// 2021-01-01 00:00:00,2021-01-01 01:00:00 | ||
/// 2021-01-01 02:00:00,2021-01-01 03:00:00 | ||
/// 2021-01-01 04:00:00,2021-01-01 05:00:00 | ||
/// \endcode | ||
/// The default delimiter is a comma, but it can be changed by setting the | ||
/// `delimiter` parameter (single character only). The time format is | ||
/// given by the accepted formats of the StringToTimeStamp function. | ||
/// | ||
/// The time ranges can be active or dead periods of time. If the time ranges | ||
/// are active periods of time, the events that are within the time ranges will | ||
/// be selected. If the time ranges are dead periods of time, the events that | ||
/// are outside the time ranges will be selected. Set the `isActiveTime` parameter | ||
/// to `true` to select the events within the time ranges (they represent active periods | ||
/// of time) or to `false` to select the events outside the time ranges (they represent | ||
/// dead periods of time). | ||
/// | ||
/// The number of events selected, rejected and the total time selected are stored in the | ||
/// metadata members. The total time selected is calculated as the sum of the time | ||
/// of all the time ranges, so it represents the total active time in the case of | ||
/// active periods of time, or the total dead time in the case of dead periods of time. | ||
/// | ||
/// ### Parameters | ||
/// * **fileWithTimes**: name of the file that contains the time ranges. | ||
/// * **isActiveTime**: if `true` (default) the time ranges represent active periods of time, if `false` the time ranges represent dead periods of time. | ||
/// * **delimiter**: delimiter used in the file with the time ranges (default is `,`). | ||
/// * **offsetTimeInSeconds**: offset time in seconds to be added to the event time (default is 0). This is useful | ||
/// to correct the time of the events if needed. This number of seconds will be added to the event time before | ||
/// checking if it is within the time ranges. | ||
/// | ||
/// ### Examples | ||
/// Examples for rml files: | ||
/// \code | ||
/// <addProcess type="TRestEventTimeSelectionProcess" name="timeSel" fileWithTimes="/path/to/file/timeperiods.txt" | ||
/// value="ON" verboseLevel="info"> | ||
/// \endcode | ||
/// <hr> | ||
/// | ||
/// \warning ** REST is under continuous development.** This documentation | ||
/// is offered to you by the REST community. Your HELP is needed to keep this code | ||
/// up to date. Your feedback will be worth to support this software, please report | ||
/// any problems/suggestions you may find while using it at [The REST Framework | ||
/// forum](http://ezpc10.unizar.es). You are welcome to contribute fixing typos, | ||
/// updating information or adding/proposing new contributions. See also our | ||
/// <a href="https://github.com/rest-for-physics/framework/blob/master/CONTRIBUTING.md">Contribution | ||
/// Guide</a>. | ||
/// | ||
/// | ||
///-------------------------------------------------------------------------- | ||
/// | ||
/// RESTsoft - Software for Rare Event Searches with TPCs | ||
/// | ||
/// History of developments: | ||
/// 2024-Jun: Use of the processing file itself (no need for external fileWithIDs) | ||
/// Alvaro Ezquerro | ||
/// | ||
/// \class TRestEventTimeSelectionProcess | ||
/// \author Alvaro Ezquerro | ||
/// | ||
/// <hr> | ||
/// | ||
|
||
#include "TRestEventTimeSelectionProcess.h" | ||
|
||
using namespace std; | ||
|
||
ClassImp(TRestEventTimeSelectionProcess); | ||
|
||
/////////////////////////////////////////////// | ||
/// \brief Default constructor | ||
/// | ||
TRestEventTimeSelectionProcess::TRestEventTimeSelectionProcess() { Initialize(); } | ||
|
||
/////////////////////////////////////////////// | ||
/// \brief Function to initialize input/output event members and define the | ||
/// section name | ||
/// | ||
void TRestEventTimeSelectionProcess::Initialize() { | ||
SetSectionName(this->ClassName()); | ||
fEvent = nullptr; | ||
fFileWithTimes = ""; | ||
fIsActiveTime = true; | ||
fDelimiter = ','; | ||
fStartEndTimes.clear(); | ||
fOffsetTimeInSeconds = 0; | ||
fNEventsRejected = 0; | ||
fNEventsSelected = 0; | ||
fTotalTimeInSeconds = 0; | ||
} | ||
|
||
/////////////////////////////////////////////// | ||
/// \brief Process initialization. | ||
/// | ||
/// | ||
void TRestEventTimeSelectionProcess::InitProcess() { | ||
// Read the file with the time ranges | ||
if (!fFileWithTimes.empty()) { | ||
fStartEndTimes.clear(); | ||
string line; | ||
ifstream file(fFileWithTimes); | ||
if (file.is_open()) { | ||
while (getline(file, line)) { | ||
if (line[0] == '#') { // understand as comment | ||
continue; | ||
} | ||
std::istringstream lineStream(line); | ||
std::string startDate, endDate; | ||
if (std::getline(lineStream, startDate, fDelimiter) && std::getline(lineStream, endDate, fDelimiter)) { | ||
fStartEndTimes.emplace_back(startDate, endDate); | ||
RESTDebug << "Start: " << startDate << " End: " << endDate << RESTendl; | ||
} | ||
} | ||
file.close(); | ||
} | ||
} | ||
fTotalTimeInSeconds = 0; | ||
for (auto id : fStartEndTimes) { | ||
TTimeStamp startTime = TTimeStamp(StringToTimeStamp(id.first), 0); | ||
TTimeStamp endTime = TTimeStamp(StringToTimeStamp(id.second), 0); | ||
fTotalTimeInSeconds += endTime.AsDouble() - startTime.AsDouble(); | ||
} | ||
fNEventsRejected = 0; | ||
fNEventsSelected = 0; | ||
} | ||
|
||
/////////////////////////////////////////////// | ||
/// \brief The main processing event function | ||
/// | ||
TRestEvent* TRestEventTimeSelectionProcess::ProcessEvent(TRestEvent* inputEvent) { | ||
fEvent = inputEvent; | ||
|
||
TTimeStamp eventTime = fEvent->GetTimeStamp(); | ||
eventTime.Add(TTimeStamp(fOffsetTimeInSeconds)); | ||
if (fIsActiveTime){ // time ranges represent active periods of time | ||
for (auto id : fStartEndTimes) { | ||
TTimeStamp startTime = TTimeStamp(StringToTimeStamp(id.first), 0); | ||
TTimeStamp endTime = TTimeStamp(StringToTimeStamp(id.second), 0); | ||
if (eventTime >= startTime && eventTime <= endTime) { | ||
fNEventsSelected++; | ||
return fEvent; | ||
} | ||
} | ||
} | ||
|
||
if (!fIsActiveTime){ // time ranges represent dead periods of time | ||
Bool_t isInDeadPeriod = false; | ||
for (auto id : fStartEndTimes) { | ||
TTimeStamp startTime = TTimeStamp(StringToTimeStamp(id.first), 0); | ||
TTimeStamp endTime = TTimeStamp(StringToTimeStamp(id.second), 0); | ||
if (eventTime >= startTime && eventTime <= endTime) { | ||
isInDeadPeriod = true; | ||
break; | ||
} | ||
} | ||
if (!isInDeadPeriod) { | ||
fNEventsSelected++; | ||
return fEvent; | ||
} | ||
} | ||
|
||
fNEventsRejected++; | ||
return nullptr; | ||
} | ||
|
||
/////////////////////////////////////////////// | ||
/// \brief Function to include required actions after all events have been | ||
/// processed. | ||
/// | ||
void TRestEventTimeSelectionProcess::EndProcess() { | ||
// Write here the jobs to do when all the events are processed | ||
} | ||
|
||
/////////////////////////////////////////////// | ||
/// \brief Function to get the cut string that reproduce the time selection | ||
/// done by this process (useful for TRestDataSet::MakeCut() for example). | ||
/// \note The cut string can be really long if there are many time ranges and | ||
/// this may cause the following error | ||
/// 'Error in <TTreeFormula::Compile>: Too many operators !' when trying to | ||
/// use the cut in TTree->Draw(). In such case, use | ||
/// \code | ||
/// ROOT::v5::TFormula::SetMaxima(10000) // or any other big enough number | ||
/// \endcode | ||
/// to increase the maximum number of operators allowed in a formula. | ||
/// | ||
std::string TRestEventTimeSelectionProcess::GetTimeStampCut(std::string timeStampObsName, Bool_t useOffset, Int_t nTimes) { | ||
std::string timeCut = ""; | ||
std::string timeStampObsNameWithOffset = timeStampObsName; | ||
if (useOffset) { | ||
timeStampObsNameWithOffset += "+" + to_string(fOffsetTimeInSeconds); | ||
} | ||
if (nTimes<0) nTimes = fStartEndTimes.size(); | ||
Int_t c = 0; | ||
for (auto id : fStartEndTimes) { | ||
if (c++ >= nTimes) break; | ||
auto startTime = StringToTimeStamp(id.first); | ||
auto endTime = StringToTimeStamp(id.second); | ||
if (!timeCut.empty()){ | ||
if (fIsActiveTime) timeCut += " || "; | ||
else timeCut += " && "; | ||
} | ||
if (!fIsActiveTime) timeCut += "!"; | ||
timeCut += "("; | ||
timeCut += timeStampObsNameWithOffset + ">=" + to_string(startTime); | ||
timeCut += "&&"; | ||
timeCut += timeStampObsNameWithOffset + "<=" + to_string(endTime); | ||
timeCut += ")"; | ||
} | ||
return timeCut; | ||
} | ||
/////////////////////////////////////////////// | ||
/// \brief Prints on screen the process data members | ||
/// | ||
void TRestEventTimeSelectionProcess::PrintMetadata() { | ||
BeginPrintProcess(); | ||
std::string typeOfTime = fIsActiveTime ? "Active" : "Dead"; | ||
|
||
RESTMetadata << "File with times: " << fFileWithTimes << RESTendl; | ||
// print periods | ||
RESTMetadata << "Offset time: " << fOffsetTimeInSeconds << " seconds" << RESTendl; | ||
RESTMetadata << typeOfTime << " time periods: " << RESTendl; | ||
for (auto id : fStartEndTimes) { | ||
RESTMetadata << id.first << " to " << id.second << RESTendl; | ||
} | ||
|
||
if ((Int_t) (fTotalTimeInSeconds / 24/3600) != 0 ) // order of days | ||
RESTMetadata << "Total " << typeOfTime << " time: " << fTotalTimeInSeconds / 24/3600 << " days" << RESTendl; | ||
else if ((Int_t) (fTotalTimeInSeconds / 3600) != 0 ) // order of hours | ||
RESTMetadata << "Total " << typeOfTime << " time: " << fTotalTimeInSeconds / 3600 << " hours" << RESTendl; | ||
else if ((Int_t) (fTotalTimeInSeconds / 60) != 0 ) // order of minutes | ||
RESTMetadata << "Total " << typeOfTime << " time: " << fTotalTimeInSeconds / 60 << " minutes" << RESTendl; | ||
else | ||
RESTMetadata << "Total " << typeOfTime << " time: " << fTotalTimeInSeconds << RESTendl; | ||
|
||
RESTMetadata << "Number of events rejected: " << fNEventsRejected << " (" | ||
<< fNEventsRejected*1. / (fNEventsRejected + fNEventsSelected) * 100 << " %)" << RESTendl; | ||
RESTMetadata << "Number of events selected: " << fNEventsSelected << " (" | ||
<< fNEventsSelected*1. / (fNEventsRejected + fNEventsSelected) * 100 << " %)" << RESTendl; | ||
|
||
EndPrintProcess(); | ||
} |