From a1a4249423108969aee75990f38ed55daf897b63 Mon Sep 17 00:00:00 2001 From: Krzysztof Kacprzak Date: Wed, 6 Mar 2024 01:48:13 -0300 Subject: [PATCH] add lifetime selection to event categorizer --- ModularDetectorAnalysis/EventCategorizer.cpp | 59 ++++---- ModularDetectorAnalysis/EventCategorizer.h | 3 + .../EventCategorizerTools.cpp | 133 ++++++++++++++++-- .../EventCategorizerTools.h | 7 +- ModularDetectorAnalysis/NTupler.cpp | 116 +++++++++++++++ ModularDetectorAnalysis/NTupler.h | 59 ++++++++ ModularDetectorAnalysis/main.cpp | 6 +- opsAnalysis/EventCategorizer.cpp | 4 +- opsAnalysis/EventCategorizer.h | 7 +- 9 files changed, 346 insertions(+), 48 deletions(-) create mode 100644 ModularDetectorAnalysis/NTupler.cpp create mode 100644 ModularDetectorAnalysis/NTupler.h diff --git a/ModularDetectorAnalysis/EventCategorizer.cpp b/ModularDetectorAnalysis/EventCategorizer.cpp index 71baea45..323e958f 100644 --- a/ModularDetectorAnalysis/EventCategorizer.cpp +++ b/ModularDetectorAnalysis/EventCategorizer.cpp @@ -33,6 +33,11 @@ bool EventCategorizer::init() INFO("Event categorization started."); // Reading user parameters + if (isOptionSet(fParams.getOptions(), kEventTimeParamKey)) + { + fEventTimeWindow = getOptionAsDouble(fParams.getOptions(), kEventTimeParamKey); + } + if (isOptionSet(fParams.getOptions(), k2gThetaDiffParamKey)) { f2gThetaDiff = getOptionAsDouble(fParams.getOptions(), k2gThetaDiffParamKey); @@ -298,34 +303,16 @@ bool EventCategorizer::exec() fToTCutAnniMax, fSourcePos, fTestType, fScatterTOFTimeDiff, fScatterTimeMin, fScatterTimeMax, fScatterAngleMin, fScatterAngleMax, fConstansTree); - // Select hits for TOF calibration, if making calibraiton - - // Selection of other type of events is currently not used - // bool is3Gamma = EventCategorizerTools::checkFor3Gamma( - // event, getStatistics(), fSaveControlHistos - // ); - // bool isPrompt = EventCategorizerTools::checkForPrompt( - // event, getStatistics(), fSaveControlHistos, fToTCutDeexMin, fToTCutDeexMax - // ); - // bool isScattered = EventCategorizerTools::checkForScatter( - // event, getStatistics(), fSaveControlHistos, fScatterTOFTimeDiff - // ); - - // JPetEvent newEvent = event; - // if (is2Gamma) - // { - // newEvent.addEventType(JPetEventType::k2Gamma); - // events.push_back(newEvent); - // } - // if(is3Gamma) newEvent.addEventType(JPetEventType::k3Gamma); - // if(isPrompt) newEvent.addEventType(JPetEventType::kPrompt); - // if(isScattered) newEvent.addEventType(JPetEventType::kScattered); - // - // if(fSaveControlHistos){ - // for(auto hit : event.getHits()){ - // getStatistics().getHisto2D("All_XYpos")->Fill(hit.getPosX(), hit.getPosY()); - // } - // } + bool isLifetime2Gamma = EventCategorizerTools::checkFor3GammaLifetime( + event, getStatistics(), fSaveControlHistos, f2gThetaDiff, f2gTimeDiff, fToTCutAnniMin, fToTCutAnniMax, fToTCutDeexMin, fToTCutDeexMax, + fSourcePos, fTestType, fScatterTOFTimeDiff, fScatterTimeMin, fScatterTimeMax, fScatterAngleMin, fScatterAngleMax, fConstansTree); + + JPetEvent newEvent = event; + if (is2Gamma || isLifetime2Gamma) + { + newEvent.addEventType(JPetEventType::k2Gamma); + events.push_back(newEvent); + } } saveEvents(events); } @@ -454,7 +441,7 @@ void EventCategorizer::initialiseHistograms() getStatistics().createHistogramWithAxes(new TH1D("tot_cut_theta", "2 gamma event after ToT cut - theta between flight vectors", 181, -0.5, 180.5), "Angle [degree]", "Number of Hit Pairs"); - // Events after cut - defined as annihilation event + // Events after cut - defined as 2 gamma annihilation event getStatistics().createHistogramWithAxes(new TH1D("ap_tot", "Annihilation pairs average ToT scaled", 201, 0.0, fToTHistoUpperLimit), "Time over Threshold [ps]", "Number of Annihilation Pairs"); @@ -550,6 +537,20 @@ void EventCategorizer::initialiseHistograms() getStatistics().createHistogramWithAxes( new TH2D("scatter_angle_time_fail", "Failed Scatter angle vs. scatter test measure", 201, -4000.0, 6000.0, 181, -0.5, 180.5), "Time Diff [ps]", "Scatter angle"); + + // Histograms for 3 gamma events + getStatistics().createHistogramWithAxes( + new TH2D("3g_rel_angles", "Sum vs. difference of two smallest relative angles in 3 gamma event", 250, 0.0, 250, 200, 0.0, 200.0), + "ang1+ang2 [deg]", "ang2-ang1 [deg]"); + + getStatistics().createHistogramWithAxes( + new TH1D("lifetime_2g_prompt", "Time difference of 2 gamma pair decay time and prompt emmission time", 201, 0.0, fEventTimeWindow), + "Time Diff [ps]", "Number of events"); + + getStatistics().createHistogramWithAxes(new TH1D("lifetime_2g_prompt_zoom", + "Time difference of 2 gamma pair decay time and prompt emmission time - closeup", 201, 0.0, + 0.25 * fEventTimeWindow), + "Time Diff [ps]", "Number of events"); } void EventCategorizer::initialiseCalibrationHistograms(bool includeTrento) diff --git a/ModularDetectorAnalysis/EventCategorizer.h b/ModularDetectorAnalysis/EventCategorizer.h index 112ce9cb..e2d644e9 100644 --- a/ModularDetectorAnalysis/EventCategorizer.h +++ b/ModularDetectorAnalysis/EventCategorizer.h @@ -44,6 +44,8 @@ class EventCategorizer : public JPetUserTask virtual bool terminate() override; protected: + const std::string kEventTimeParamKey = "EventFinder_EventTime_double"; + const std::string k2gThetaDiffParamKey = "EventCategorizer_2gThetaDiff_double"; const std::string k2gTimeDiffParamKey = "EventCategorizer_2gTimeDiff_double"; @@ -86,6 +88,7 @@ class EventCategorizer : public JPetUserTask void saveEvents(const std::vector& event); boost::property_tree::ptree fConstansTree; + double fEventTimeWindow = 5000.0; double fScatterTOFTimeDiff = 2000.0; double fScatterTimeMin = 0.0; double fScatterTimeMax = 3000.0; diff --git a/ModularDetectorAnalysis/EventCategorizerTools.cpp b/ModularDetectorAnalysis/EventCategorizerTools.cpp index b66a806d..411770c7 100644 --- a/ModularDetectorAnalysis/EventCategorizerTools.cpp +++ b/ModularDetectorAnalysis/EventCategorizerTools.cpp @@ -329,24 +329,28 @@ bool EventCategorizerTools::checkFor2Gamma(const JPetPhysRecoHit* firstHit, cons /** * Method for determining type of event - 3Gamma */ -/*bool EventCategorizerTools::checkFor3Gamma(const JPetEvent& event, JPetStatistics& stats, bool saveHistos) +bool EventCategorizerTools::checkFor3Gamma(const JPetEvent& event, JPetStatistics& stats, bool saveHistos) { if (event.getHits().size() < 3) + { return false; + } + + // Iteration over the hits in the event for (uint i = 0; i < event.getHits().size(); i++) { for (uint j = i + 1; j < event.getHits().size(); j++) { for (uint k = j + 1; k < event.getHits().size(); k++) { - JPetBaseHit firstHit = event.getHits().at(i); - JPetBaseHit secondHit = event.getHits().at(j); - JPetBaseHit thirdHit = event.getHits().at(k); + auto firstHit = dynamic_cast(event.getHits().at(i)); + auto secondHit = dynamic_cast(event.getHits().at(j)); + auto thirdHit = dynamic_cast(event.getHits().at(k)); vector thetaAngles; - thetaAngles.push_back(firstHit.getScin().getSlot().getTheta()); - thetaAngles.push_back(secondHit.getScin().getSlot().getTheta()); - thetaAngles.push_back(thirdHit.getScin().getSlot().getTheta()); + thetaAngles.push_back(firstHit->getScin().getSlot().getTheta()); + thetaAngles.push_back(secondHit->getScin().getSlot().getTheta()); + thetaAngles.push_back(thirdHit->getScin().getSlot().getTheta()); sort(thetaAngles.begin(), thetaAngles.end()); vector relativeAngles; @@ -359,13 +363,124 @@ bool EventCategorizerTools::checkFor2Gamma(const JPetPhysRecoHit* firstHit, cons if (saveHistos) { - stats.getHisto2D("3Gamma_Angles")->Fill(transformedX, transformedY); + stats.getHisto2D("3g_rel_angles")->Fill(transformedX, transformedY); } } } } return true; -}*/ +} + +bool EventCategorizerTools::checkFor3GammaLifetime(const JPetEvent& event, JPetStatistics& stats, bool saveHistos, double maxThetaDiff, + double maxTimeDiff, double totCutAnniMin, double totCutAnniMax, double totCutDeexMin, + double totCutDeexMax, const TVector3& sourcePos, ScatterTestType testType, double scatterTestValue, + double scatterTimeMin, double scatterTimeMax, double scatterAngleMin, double scatterAngleMax, + boost::property_tree::ptree& calibTree) +{ + if (event.getHits().size() < 3) + { + return false; + } + + vector prompts; + vector> annihilaions; + + // First check if any of the hits in the event is prompt based on TOT selection + for (uint i = 0; i < event.getHits().size(); i++) + { + auto promptHit = dynamic_cast(event.getHits().at(i)); + if (checkToT(promptHit, totCutDeexMin, totCutDeexMax)) + { + prompts.push_back(promptHit); + } + } + if (prompts.size() == 0) + { + return false; + } + + // Then looking for annihilation back to back pairs + for (uint i = 0; i < event.getHits().size(); i++) + { + auto firstHit = dynamic_cast(event.getHits().at(i)); + if (!firstHit) + { + continue; + } + + for (uint j = i + 1; j < event.getHits().size(); j++) + { + auto secondHit = dynamic_cast(event.getHits().at(j)); + if (!secondHit) + { + continue; + } + + // Change order or hits, if needed + if (event.getHits().at(i)->getTime() > event.getHits().at(j)->getTime()) + { + firstHit = dynamic_cast(event.getHits().at(j)); + secondHit = dynamic_cast(event.getHits().at(i)); + } + + // Skip if scatter + if (checkForScatter(firstHit, secondHit, stats, false, testType, scatterTestValue, scatterTimeMin, scatterTimeMax, scatterAngleMin, + scatterAngleMax, calibTree)) + { + continue; + } + + if (checkFor2Gamma(firstHit, secondHit, stats, false, maxThetaDiff, maxTimeDiff, totCutAnniMin, totCutAnniMax, sourcePos)) + { + annihilaions.push_back(make_pair(firstHit, secondHit)); + } + } + } + + if (annihilaions.size() == 0) + { + return false; + } + + bool isLifetimeEvent = false; + + // Iterating over all combinations of found pairs and prompt photons + for (auto pair2g : annihilaions) + { + for (auto prompt : prompts) + { + // Check if neighter of the two annihilation photons are scattered from prompt photon + if (checkForScatter(prompt, pair2g.first, stats, false, testType, scatterTestValue, scatterTimeMin, scatterTimeMax, scatterAngleMin, + scatterAngleMax, calibTree) || + checkForScatter(prompt, pair2g.second, stats, false, testType, scatterTestValue, scatterTimeMin, scatterTimeMax, scatterAngleMin, + scatterAngleMax, calibTree)) + { + continue; + } + + isLifetimeEvent = true; + + // Calculate the annihilation point position + TVector3 annhilationPoint = calculateAnnihilationPoint(pair2g.first, pair2g.second); + + // Caculate event times - annihilation + auto tof = calculateTOFByConvention(pair2g.first, pair2g.second); + double annihTime1 = pair2g.first->getTime() - tof; + double annihTime2 = pair2g.second->getTime() - tof; + double promptTime = prompt->getTime() - tof; + // Calculate lifetime + double lifetime = (annihTime1 + annihTime2) / 2.0 - promptTime; + + if (saveHistos) + { + stats.fillHistogram("lifetime_2g_prompt", lifetime); + stats.fillHistogram("lifetime_2g_prompt_zoom", lifetime); + } + } + } + + return isLifetimeEvent; +} /** * Method for determining type of event - prompt diff --git a/ModularDetectorAnalysis/EventCategorizerTools.h b/ModularDetectorAnalysis/EventCategorizerTools.h index 8417eab6..f2486fb2 100644 --- a/ModularDetectorAnalysis/EventCategorizerTools.h +++ b/ModularDetectorAnalysis/EventCategorizerTools.h @@ -77,7 +77,12 @@ class EventCategorizerTools // static std::vector getLORs(const JPetEvent& event, JPetStatistics& stats, bool saveHistos, double maxTOF, double maxScatter, // double totCutAnniMin, double totCutAnniMax); - // static bool checkFor3Gamma(const JPetEvent& event, JPetStatistics& stats, bool saveHistos); + static bool checkFor3Gamma(const JPetEvent& event, JPetStatistics& stats, bool saveHistos); + + static bool checkFor3GammaLifetime(const JPetEvent& event, JPetStatistics& stats, bool saveHistos, double maxThetaDiff, double maxTimeDiff, + double totCutAnniMin, double totCutAnniMax, double totCutDeexMin, double totCutDeexMax, + const TVector3& sourcePos, ScatterTestType testType, double scatterTestValue, double scatterTimeMin, + double scatterTimeMax, double scatterAngleMin, double scatterAngleMax, boost::property_tree::ptree& calibTree); // static bool checkForPrompt(const JPetEvent& event, JPetStatistics& stats, bool saveHistos, double deexToTCutMin, double deexToTCutMax); diff --git a/ModularDetectorAnalysis/NTupler.cpp b/ModularDetectorAnalysis/NTupler.cpp new file mode 100644 index 00000000..fa22fee4 --- /dev/null +++ b/ModularDetectorAnalysis/NTupler.cpp @@ -0,0 +1,116 @@ +/** + * @copyright Copyright 2024 The J-PET Framework Authors. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may find a copy of the License in the LICENCE file. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @file Ntupler.cpp + */ + +#include "NTupler.h" +#include "../ModularDetectorAnalysis/HitFinderTools.h" +#include +#include + +using namespace jpet_options_tools; +using namespace std; + +NTupler::NTupler(const char* name) : JPetUserTask(name) {} + +bool NTupler::init() +{ + INFO("Started reduction of data to ntuples."); + + fOutputEvents = new JPetTimeWindow("JPetEvent"); + + if (isOptionSet(fParams.getOptions(), "inputFile_std::string")) + { + fOutFileName = getOptionAsString(fParams.getOptions(), "inputFile_std::string"); + } + + if (isOptionSet(fParams.getOptions(), "outputPath_std::string")) + { + fOutFilePath = getOptionAsString(fParams.getOptions(), "outputPath_std::string"); + } + + // initialize output file and tree + if (fOutFileName.find("unk.evt.root") != std::string::npos) + { + fOutFileName.replace(fOutFileName.find("unk.evt.root"), std::string::npos, "ntu.root"); + } + + if (!fOutFilePath.empty()) + { + size_t filename_pos = fOutFileName.find("dabc"); + fOutFileName.replace(0, filename_pos - 1, fOutFilePath); + } + + fOutFile = new TFile(fOutFileName.c_str(), "RECREATE"); + fOutTree = new TTree("T", "JPET Events"); + + fOutTree->Branch("nhits", &fNumberOfHits, "nhits/b"); + fOutTree->Branch("times", &fHitTimes); + fOutTree->Branch("pos", &fHitPos); + fOutTree->Branch("tots", &fHitTOTs); + fOutTree->Branch("scins", &fHitScinIDs); + + return true; +} + +bool NTupler::exec() +{ + if (auto timeWindow = dynamic_cast(fEvent)) + { + + int n_events = timeWindow->getNumberOfEvents(); + + for (int entry = 0; entry < n_events; ++entry) + { + const JPetEvent& event = dynamic_cast(timeWindow->operator[](entry)); + + const auto& hits = event.getHits(); + fNumberOfHits = event.getHits().size(); + + for (auto& hit : hits) + { + // Writing time in nanoseconds + fHitTimes.push_back(hit->getTime() / 1000.); + fHitPos.push_back(hit->getPos()); + fHitTOTs.push_back(hit->getEnergy()); + fHitScinIDs.push_back(hit->getScin().getID()); + } + + fOutTree->Fill(); + resetRow(); + } + } + else + { + return false; + } + return true; +} + +bool NTupler::terminate() +{ + fOutTree->Write(); + fOutFile->Close(); + + INFO("Finished reduction of data to ntuples."); + return true; +} + +void NTupler::resetRow() +{ + fNumberOfHits = 0; + fHitTimes.clear(); + fHitPos.clear(); + fHitTOTs.clear(); + fHitScinIDs.clear(); +} diff --git a/ModularDetectorAnalysis/NTupler.h b/ModularDetectorAnalysis/NTupler.h new file mode 100644 index 00000000..591ede33 --- /dev/null +++ b/ModularDetectorAnalysis/NTupler.h @@ -0,0 +1,59 @@ +/** + * @copyright Copyright 2024 The J-PET Framework Authors. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may find a copy of the License in the LICENCE file. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @file Ntupler.h + */ + +#ifndef NTUPLER_H +#define NTUPLER_H + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +class NTupler : public JPetUserTask +{ + +public: + NTupler(const char* name); + virtual ~NTupler() {} + virtual bool init() override; + virtual bool exec() override; + virtual bool terminate() override; + +protected: + void resetRow(); + + TFile* fOutFile; + TTree* fOutTree; + std::string fOutFileName; + std::string fOutFilePath; + + // ntuple components + std::vector fHitTimes; + std::vector fHitPos; + std::vector fHitTOTs; + std::vector fHitScinIDs; + + UChar_t fNumberOfHits; +}; + +#endif /* !NTUPLER_H */ diff --git a/ModularDetectorAnalysis/main.cpp b/ModularDetectorAnalysis/main.cpp index d0fc043e..64e93d4e 100644 --- a/ModularDetectorAnalysis/main.cpp +++ b/ModularDetectorAnalysis/main.cpp @@ -1,5 +1,5 @@ /** - * @copyright Copyright 2021 The J-PET Framework Authors. All rights reserved. + * @copyright Copyright 2024 The J-PET Framework Authors. All rights reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may find a copy of the License in the LICENCE file. @@ -16,9 +16,11 @@ #include "EventCategorizer.h" #include "EventFinder.h" #include "HitFinder.h" +// #include "NTupler.h" #include "SignalFinder.h" #include "SignalTransformer.h" #include "TimeWindowCreator.h" + #include using namespace std; @@ -34,6 +36,7 @@ int main(int argc, const char* argv[]) manager.registerTask("HitFinder"); manager.registerTask("EventFinder"); manager.registerTask("EventCategorizer"); + // manager.registerTask("NTupler"); manager.useTask("TimeWindowCreator", "hld", "tslot"); manager.useTask("SignalFinder", "tslot", "pm.sig"); @@ -41,6 +44,7 @@ int main(int argc, const char* argv[]) manager.useTask("HitFinder", "mtx.sig", "hits"); manager.useTask("EventFinder", "hits", "unk.evt"); manager.useTask("EventCategorizer", "unk.evt", "cat.evt"); + // manager.useTask("NTupler", "cat.evt", "ntu"); manager.run(argc, argv); } diff --git a/opsAnalysis/EventCategorizer.cpp b/opsAnalysis/EventCategorizer.cpp index 7955b959..f3ff87e2 100644 --- a/opsAnalysis/EventCategorizer.cpp +++ b/opsAnalysis/EventCategorizer.cpp @@ -128,7 +128,7 @@ bool EventCategorizer::exec() getStatistics().fillHistogram("HitMult", event_type); - ReconHitsCalculation(hits, event_type = UNKNOWN, *time_window_mc); + reconHitsCalculation(hits, event_type = UNKNOWN, *time_window_mc); hits.clear(); hits_tot.clear(); @@ -148,7 +148,7 @@ bool EventCategorizer::exec() return true; } -void EventCategorizer::ReconHitsCalculation(vector hits, EvtType& event_type, const JPetTimeWindowMC& time_window_mc) +void EventCategorizer::reconHitsCalculation(vector hits, EvtType& event_type, const JPetTimeWindowMC& time_window_mc) { // Reconstructed hits -- Annihilation Point ( Trilateration Method ) (Alek's code) const JPetPhysRecoHit* hit1 = hits.at(0); diff --git a/opsAnalysis/EventCategorizer.h b/opsAnalysis/EventCategorizer.h index 9a4692a2..a079c73c 100644 --- a/opsAnalysis/EventCategorizer.h +++ b/opsAnalysis/EventCategorizer.h @@ -32,10 +32,6 @@ using namespace std; class JPetWriter; -#ifdef __CINT__ -#define override -#endif - static const double kLightVelocity_cm_ns = 29.9792458; enum EvtType @@ -77,7 +73,6 @@ class EventCategorizer : public JPetUserTask double meanTime_3Hits; - double Magnitude(TVector3 p1); void saveEvents(const std::vector& event); void initialiseHistograms(); @@ -85,7 +80,7 @@ class EventCategorizer : public JPetUserTask vector tot(const JPetEvent* event); vector scatTest(vector hits_tot); - void ReconHitsCalculation(vector hits, EvtType& event_type, const JPetTimeWindowMC& time_window_mc); + void reconHitsCalculation(vector hits, EvtType& event_type, const JPetTimeWindowMC& time_window_mc); double scatterTest(vector hits, EvtType event_type);