Skip to content

Commit

Permalink
add lifetime selection to event categorizer
Browse files Browse the repository at this point in the history
  • Loading branch information
kkacprzak committed Mar 6, 2024
1 parent 89e61ad commit a1a4249
Show file tree
Hide file tree
Showing 9 changed files with 346 additions and 48 deletions.
59 changes: 30 additions & 29 deletions ModularDetectorAnalysis/EventCategorizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions ModularDetectorAnalysis/EventCategorizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -86,6 +88,7 @@ class EventCategorizer : public JPetUserTask
void saveEvents(const std::vector<JPetEvent>& event);

boost::property_tree::ptree fConstansTree;
double fEventTimeWindow = 5000.0;
double fScatterTOFTimeDiff = 2000.0;
double fScatterTimeMin = 0.0;
double fScatterTimeMax = 3000.0;
Expand Down
133 changes: 124 additions & 9 deletions ModularDetectorAnalysis/EventCategorizerTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const JPetPhysRecoHit*>(event.getHits().at(i));
auto secondHit = dynamic_cast<const JPetPhysRecoHit*>(event.getHits().at(j));
auto thirdHit = dynamic_cast<const JPetPhysRecoHit*>(event.getHits().at(k));

vector<double> 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<double> relativeAngles;
Expand All @@ -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<const JPetPhysRecoHit*> prompts;
vector<pair<const JPetPhysRecoHit*, const JPetPhysRecoHit*>> 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<const JPetPhysRecoHit*>(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<const JPetPhysRecoHit*>(event.getHits().at(i));
if (!firstHit)
{
continue;
}

for (uint j = i + 1; j < event.getHits().size(); j++)
{
auto secondHit = dynamic_cast<const JPetPhysRecoHit*>(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<const JPetPhysRecoHit*>(event.getHits().at(j));
secondHit = dynamic_cast<const JPetPhysRecoHit*>(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
Expand Down
7 changes: 6 additions & 1 deletion ModularDetectorAnalysis/EventCategorizerTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,12 @@ class EventCategorizerTools
// static std::vector<JPetEvent> 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);

Expand Down
116 changes: 116 additions & 0 deletions ModularDetectorAnalysis/NTupler.cpp
Original file line number Diff line number Diff line change
@@ -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 <JPetOptionsTools/JPetOptionsTools.h>
#include <iostream>

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<const JPetTimeWindow* const>(fEvent))
{

int n_events = timeWindow->getNumberOfEvents();

for (int entry = 0; entry < n_events; ++entry)
{
const JPetEvent& event = dynamic_cast<const JPetEvent&>(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();
}
Loading

0 comments on commit a1a4249

Please sign in to comment.