Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 162 additions & 10 deletions Common/Core/PID/PIDTOF.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,136 @@ class TOFResoParamsV2 : public o2::tof::Parameters<13>
TGraph* gNegEtaTimeCorr = nullptr; /// Time shift correction for negative tracks
};

/// \brief Next implementation class to store TOF response parameters for exp. times
class TOFResoParamsV3 : public o2::tof::Parameters<13>
{
public:
TOFResoParamsV3() : Parameters(std::array<std::string, 13>{"TrkRes.Pi.P0", "TrkRes.Pi.P1", "TrkRes.Pi.P2", "TrkRes.Pi.P3", "time_resolution",
"TrkRes.Ka.P0", "TrkRes.Ka.P1", "TrkRes.Ka.P2", "TrkRes.Ka.P3",
"TrkRes.Pr.P0", "TrkRes.Pr.P1", "TrkRes.Pr.P2", "TrkRes.Pr.P3"},
"TOFResoParamsV3")
{
setParameters(std::array<float, 13>{0.008, 0.008, 0.002, 40.0, 60.0,
0.008, 0.008, 0.002, 40.0,
0.008, 0.008, 0.002, 40.0});
} // Default constructor with default parameters

~TOFResoParamsV3() = default;

// Momentum shift for charge calibration
void setMomentumChargeShiftParameters(std::unordered_map<std::string, float> const& pars)
{
if (pars.count("Shift.etaN") == 0) { // If the map does not contain the number of eta bins, we assume that no correction has to be applied
mEtaN = 0;
return;
}
mEtaN = static_cast<int>(pars.at("Shift.etaN"));
if (mEtaN <= 0) {
LOG(fatal) << "TOFResoParamsV3 shift: etaN must be positive";
}
mEtaStart = pars.at("Shift.etaStart");
mEtaStop = pars.at("Shift.etaStop");
if (mEtaStart >= mEtaStop) {
LOG(fatal) << "TOFResoParamsV3 shift: etaStart must be smaller than etaStop";
}
mInvEtaWidth = 1.f / ((mEtaStop - mEtaStart) / mEtaN);
mContent.clear();
mContent.resize(mEtaN);
for (int i = 0; i < mEtaN; ++i) {
mContent[i] = pars.at(Form("Shift.etaC%i", i));
}
}

float getMomentumChargeShift(float eta) const
{
if (mEtaN == 0) { // No correction
// LOG(info) << "TOFResoParamsV3 shift: no correction mEtaN is " << mEtaN;
return 0.f;
}
const int& etaIndex = (eta <= mEtaStart) ? 0 : (eta >= mEtaStop ? (mEtaN - 1) : (eta - mEtaStart) * mInvEtaWidth);
// LOG(info) << "TOFResoParamsV3 shift: correction for eta " << eta << " is for index " << etaIndex << " = " << shift;
return mContent.at(etaIndex);
}

void printMomentumChargeShiftParameters() const
{
LOG(info) << "TOF momentum shift parameters";
LOG(info) << "etaN: " << mEtaN;
LOG(info) << "etaStart: " << mEtaStart;
LOG(info) << "etaStop: " << mEtaStop;
LOG(info) << "content size " << mContent.size();
for (int i = 0; i < mEtaN; ++i) {
LOG(info) << "etaC" << i << ": " << mContent[i];
}
}

// Time shift for post calibration
void setTimeShiftParameters(std::unordered_map<std::string, float> const& pars, bool positive)
{
std::string baseOpt = positive ? "TimeShift.Pos." : "TimeShift.Neg.";

if (pars.count(baseOpt + "GetN") == 0) { // If the map does not contain the number of eta bins, we assume that no correction has to be applied
return;
}
const int nPoints = static_cast<int>(pars.at(baseOpt + "GetN"));
if (nPoints <= 0) {
LOG(fatal) << "TOFResoParamsV3 shift: time must be positive";
}
TGraph graph;
for (int i = 0; i < nPoints; ++i) {
graph.AddPoint(pars.at(Form("TimeShift.eta%i", i)), pars.at(Form("TimeShift.cor%i", i)));
}
setTimeShiftParameters(&graph, positive);
}
void setTimeShiftParameters(std::string const& filename, std::string const& objname, bool positive)
{
TFile f(filename.c_str(), "READ");
if (f.IsOpen()) {
if (positive) {
f.GetObject(objname.c_str(), gPosEtaTimeCorr);
} else {
f.GetObject(objname.c_str(), gNegEtaTimeCorr);
}
f.Close();
}
LOG(info) << "Set the Time Shift parameters from file " << filename << " and object " << objname << " for " << (positive ? "positive" : "negative");
}
void setTimeShiftParameters(TGraph* g, bool positive)
{
if (positive) {
gPosEtaTimeCorr = g;
} else {
gNegEtaTimeCorr = g;
}
LOG(info) << "Set the Time Shift parameters from object " << g->GetName() << " " << g->GetTitle() << " for " << (positive ? "positive" : "negative");
}
float getTimeShift(float eta, int16_t sign) const
{
if (sign > 0) {
if (!gPosEtaTimeCorr) {
return 0.f;
}
return gPosEtaTimeCorr->Eval(eta);
}
if (!gNegEtaTimeCorr) {
return 0.f;
}
return gNegEtaTimeCorr->Eval(eta);
}

private:
// Charge calibration
int mEtaN = 0; // Number of eta bins, 0 means no correction
float mEtaStart = 0.f;
float mEtaStop = 0.f;
float mInvEtaWidth = 9999.f;
std::vector<float> mContent;

// Time shift for post calibration
TGraph* gPosEtaTimeCorr = nullptr; /// Time shift correction for positive tracks
TGraph* gNegEtaTimeCorr = nullptr; /// Time shift correction for negative tracks
};

/// \brief Class to handle the the TOF detector response for the expected time
template <typename TrackType, o2::track::PID::ID id>
class ExpTimes
Expand Down Expand Up @@ -279,16 +409,17 @@ class ExpTimes
/// Gets the expected signal of the track of interest under the PID assumption corrected for shifts in expected momentum
/// \param parameters Parameters to correct for the momentum shift
/// \param track Track of interest
static float GetCorrectedExpectedSignal(const TOFResoParamsV2& parameters, const TrackType& track)
template <typename ParamType>
static float GetCorrectedExpectedSignal(const ParamType& parameters, const TrackType& track)
{
if (!track.hasTOF()) {
return defaultReturnValue;
}
if (track.trackType() == o2::aod::track::Run2Track) {
return ComputeExpectedTime(track.tofExpMom() * kCSPEDDInv / (1.f + track.sign() * parameters.getShift(track.eta())), track.length());
return ComputeExpectedTime(track.tofExpMom() * kCSPEDDInv / (1.f + track.sign() * parameters.getMomentumChargeShift(track.eta())), track.length());
}
LOG(debug) << "TOF exp. mom. " << track.tofExpMom() << " shifted = " << track.tofExpMom() / (1.f + track.sign() * parameters.getShift(track.eta()));
return ComputeExpectedTime(track.tofExpMom() / (1.f + track.sign() * parameters.getShift(track.eta())), track.length()) + parameters.getTimeShift(track.eta(), track.sign());
LOG(debug) << "TOF exp. mom. " << track.tofExpMom() << " shifted = " << track.tofExpMom() / (1.f + track.sign() * parameters.getMomentumChargeShift(track.eta()));
return ComputeExpectedTime(track.tofExpMom() / (1.f + track.sign() * parameters.getMomentumChargeShift(track.eta())), track.length()) + parameters.getTimeShift(track.eta(), track.sign());
}

/// Gets the expected resolution of the t-texp-t0
Expand All @@ -297,7 +428,8 @@ class ExpTimes
/// \param track Track of interest
/// \param tofSignal TOF signal of the track of interest
/// \param collisionTimeRes Collision time resolution of the track of interest
static float GetExpectedSigma(const TOFResoParamsV2& parameters, const TrackType& track, const float tofSignal, const float collisionTimeRes)
template <typename ParamType>
static float GetExpectedSigma(const ParamType& parameters, const TrackType& track, const float tofSignal, const float collisionTimeRes)
{
const float& mom = track.p();
if (mom <= 0) {
Expand All @@ -323,29 +455,49 @@ class ExpTimes
/// Gets the expected resolution of the t-texp-t0
/// \param parameters Detector response parameters
/// \param track Track of interest
static float GetExpectedSigma(const TOFResoParamsV2& parameters, const TrackType& track) { return GetExpectedSigma(parameters, track, track.tofSignal(), track.tofEvTimeErr()); }
template <typename ParamType>
static float GetExpectedSigma(const ParamType& parameters, const TrackType& track)
{
return GetExpectedSigma(parameters, track, track.tofSignal(), track.tofEvTimeErr());
}

/// Gets the expected resolution of the time measurement, uses the expected time and no event time resolution
/// \param parameters Parameters to use to compute the expected resolution
/// \param track Track of interest
static float GetExpectedSigmaTracking(const TOFResoParamsV2& parameters, const TrackType& track) { return GetExpectedSigma(parameters, track, GetCorrectedExpectedSignal(parameters, track), 0.f); }
template <typename ParamType>
static float GetExpectedSigmaTracking(const ParamType& parameters, const TrackType& track)
{
return GetExpectedSigma(parameters, track, GetCorrectedExpectedSignal(parameters, track), 0.f);
}

/// Gets the number of sigmas with respect the expected time
/// \param parameters Detector response parameters
/// \param track Track of interest
/// \param collisionTime Collision time
/// \param collisionTimeRes Collision time resolution of the track of interest
static float GetSeparation(const TOFResoParamsV2& parameters, const TrackType& track, const float collisionTime, const float resolution) { return track.hasTOF() ? (track.tofSignal() - collisionTime - GetCorrectedExpectedSignal(parameters, track)) / resolution : defaultReturnValue; }
template <typename ParamType>
static float GetSeparation(const ParamType& parameters, const TrackType& track, const float collisionTime, const float resolution)
{
return track.hasTOF() ? (track.tofSignal() - collisionTime - GetCorrectedExpectedSignal(parameters, track)) / resolution : defaultReturnValue;
}

/// Gets the number of sigmas with respect the expected time
/// \param parameters Detector response parameters
/// \param track Track of interest
static float GetSeparation(const TOFResoParamsV2& parameters, const TrackType& track, const float resolution) { return GetSeparation(parameters, track, track.tofEvTime(), resolution); }
template <typename ParamType>
static float GetSeparation(const ParamType& parameters, const TrackType& track, const float resolution)
{
return GetSeparation(parameters, track, track.tofEvTime(), resolution);
}

/// Gets the number of sigmas with respect the expected time
/// \param parameters Detector response parameters
/// \param track Track of interest
static float GetSeparation(const TOFResoParamsV2& parameters, const TrackType& track) { return GetSeparation(parameters, track, track.tofEvTime(), GetExpectedSigma(parameters, track)); }
template <typename ParamType>
static float GetSeparation(const ParamType& parameters, const TrackType& track)
{
return GetSeparation(parameters, track, track.tofEvTime(), GetExpectedSigma(parameters, track));
}
};

/// \brief Class to convert the trackTime to the tofSignal used for PID
Expand Down
8 changes: 6 additions & 2 deletions Common/DataModel/PIDResponse.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,10 @@ DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeTOFT0AC, isEvTimeTOFT0AC, //! True if the Eve

namespace pidtofsignal
{
DECLARE_SOA_COLUMN(TOFSignal, tofSignal, float); //! TOF signal from track time
DECLARE_SOA_COLUMN(TOFSignal, tofSignal, float); //! TOF signal from track time
DECLARE_SOA_DYNAMIC_COLUMN(EventCollisionTime, eventCollisionTime, //! Event collision time used for the track. Needs the TOF
[](float signal, float tMinusTexp, float texp) -> float { return texp + tMinusTexp - signal; });

} // namespace pidtofsignal

namespace pidtofbeta
Expand Down Expand Up @@ -528,7 +531,8 @@ DEFINE_UNWRAP_NSIGMA_COLUMN(TOFNSigmaAl, tofNSigmaAl); //! Unwrapped (float) nsi
} // namespace pidtof_tiny

DECLARE_SOA_TABLE(TOFSignal, "AOD", "TOFSignal", //! Table of the TOF signal
pidtofsignal::TOFSignal);
pidtofsignal::TOFSignal,
pidtofsignal::EventCollisionTime<pidtofsignal::TOFSignal>);

DECLARE_SOA_TABLE(pidTOFFlags, "AOD", "pidTOFFlags", //! Table of the flags for TOF signal quality on the track level
pidflags::GoodTOFMatch);
Expand Down
36 changes: 22 additions & 14 deletions Common/TableProducer/PID/pidTOFBase.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include "Common/DataModel/EventSelection.h"
#include "Common/DataModel/FT0Corrected.h"
#include "Common/DataModel/Multiplicity.h"
#include "Framework/HistogramRegistry.h"
#include "Framework/runDataProcessing.h"
#include "TableHelper.h"
#include "pidTOFBase.h"

Expand All @@ -39,15 +41,6 @@ using namespace o2::pid;
using namespace o2::framework::expressions;
using namespace o2::track;

void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions)
{
std::vector<ConfigParamSpec> options{{"add-qa", VariantType::Int, 0, {"Legacy. No effect."}},
{"evtime", VariantType::Int, 1, {"Produce the table for the Event Time"}}};
std::swap(workflowOptions, options);
}

#include "Framework/runDataProcessing.h"

/// Selection criteria for tracks used for TOF event time
float trackDistanceForGoodMatch = 999.f;
float trackDistanceForGoodMatchLowMult = 999.f;
Expand All @@ -69,6 +62,8 @@ bool isTrackGoodMatchForTOFPID(const Run3Trks::iterator& tr, const Run3Cols& /*e
struct tofSignal {
o2::framework::Produces<o2::aod::TOFSignal> table;
o2::framework::Produces<o2::aod::pidTOFFlags> tableFlags;
HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject};

bool enableTable = false; // Flag to check if the TOF signal table is requested or not
bool enableTableFlags = false; // Flag to check if the TOF signal flags table is requested or not
// CCDB configuration
Expand All @@ -78,6 +73,7 @@ struct tofSignal {
Configurable<float> distanceForGoodMatch{"distanceForGoodMatch", 999.f, "Maximum distance to consider a good match"};
Configurable<float> distanceForGoodMatchLowMult{"distanceForGoodMatchLowMult", 999.f, "Maximum distance to consider a good match for low multiplicity events"};
Configurable<int> multThreshold{"multThreshold", 0, "Multiplicity threshold to consider a low multiplicity event"};
Configurable<bool> enableQaHistograms{"enableQaHistograms", false, "Flag to enable the QA histograms"};

void init(o2::framework::InitContext& initContext)
{
Expand All @@ -101,6 +97,13 @@ struct tofSignal {
trackDistanceForGoodMatchLowMult = distanceForGoodMatchLowMult;
multiplicityThreshold = multThreshold;
LOG(info) << "Configuring selections for good match: " << trackDistanceForGoodMatch << " low mult " << trackDistanceForGoodMatchLowMult << " mult. threshold " << multiplicityThreshold;
if (!enableQaHistograms) {
return;
}
histos.add("tofSignal", "tofSignal", kTH1D, {{1000, -1000, 1000000, "tofSignal (ps)"}});
if (enableTableFlags) {
histos.add("goodForPIDFlags", "goodForPIDFlags", kTH1D, {{3, 0, 3, "flags"}});
}
}
void processRun3(Run3Trks const& tracks, Run3Cols const& collisions)
{
Expand All @@ -112,11 +115,19 @@ struct tofSignal {
tableFlags.reserve(tracks.size());
}
for (auto& t : tracks) {
table(o2::pid::tof::TOFSignal<Run3Trks::iterator>::GetTOFSignal(t));
const auto s = o2::pid::tof::TOFSignal<Run3Trks::iterator>::GetTOFSignal(t);
if (enableQaHistograms) {
histos.fill(HIST("tofSignal"), s);
}
table(s);
if (!enableTableFlags) {
continue;
}
tableFlags(isTrackGoodMatchForTOFPID(t, collisions));
const auto b = isTrackGoodMatchForTOFPID(t, collisions);
if (enableQaHistograms) {
histos.fill(HIST("goodForPIDFlags"), s);
}
tableFlags(b);
}
}
PROCESS_SWITCH(tofSignal, processRun3, "Process Run3 data i.e. input is TrackIU", true);
Expand Down Expand Up @@ -537,9 +548,6 @@ struct tofEventTime {
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
{
auto workflow = WorkflowSpec{adaptAnalysisTask<tofSignal>(cfgc)};
if (!cfgc.options().get<int>("evtime")) {
return workflow;
}
workflow.push_back(adaptAnalysisTask<tofEventTime>(cfgc));
return workflow;
}
Loading