diff --git a/Common/DataModel/PIDResponseTOF.h b/Common/DataModel/PIDResponseTOF.h index aa3d768c8d2..5edfe931ad8 100644 --- a/Common/DataModel/PIDResponseTOF.h +++ b/Common/DataModel/PIDResponseTOF.h @@ -27,6 +27,7 @@ #include "Framework/AnalysisDataModel.h" #include "ReconstructionDataFormats/PID.h" #include "Framework/Logger.h" +#include "Common/Core/PID/PIDTOF.h" namespace o2::aod { @@ -209,6 +210,65 @@ perSpeciesWrapper(tofExpSignalDiff); } // namespace pidutils +// Extra tables +namespace pidflags +{ + +namespace enums +{ +enum PIDFlags : uint8_t { + EvTimeUndef = 0x0, // Event collision not set, corresponding to the LHC Fill event time + EvTimeTOF = 0x1, // Event collision time from TOF + EvTimeT0AC = 0x2, // Event collision time from the FT0AC + EvTimeTOFT0AC = 0x4 // Event collision time from the TOF and FT0AC +}; +} + +DECLARE_SOA_COLUMN(GoodTOFMatch, goodTOFMatch, bool); //! Bool for the TOF PID information on the single track information +DECLARE_SOA_COLUMN(TOFFlags, tofFlags, uint8_t); //! Flag for the complementary TOF PID information for the event time +DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeDefined, isEvTimeDefined, //! True if the Event Time was computed with any method i.e. there is a usable event time + [](uint8_t flags) -> bool { return (flags > 0); }); +DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeTOF, isEvTimeTOF, //! True if the Event Time was computed with the TOF + [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeTOF) == enums::PIDFlags::EvTimeTOF; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeT0AC, isEvTimeT0AC, //! True if the Event Time was computed with the T0AC + [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeT0AC) == enums::PIDFlags::EvTimeT0AC; }); +DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeTOFT0AC, isEvTimeTOFT0AC, //! True if the Event Time was computed with the TOF and T0AC + [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeTOFT0AC) == enums::PIDFlags::EvTimeTOFT0AC; }); + +} // namespace pidflags + +DECLARE_SOA_TABLE(pidTOFFlags, "AOD", "pidTOFFlags", //! Table of the flags for TOF signal quality on the track level + pidflags::GoodTOFMatch); + +DECLARE_SOA_TABLE(pidEvTimeFlags, "AOD", "pidEvTimeFlags", //! Table of the PID flags for the event time tables + pidflags::TOFFlags, + pidflags::IsEvTimeDefined, + pidflags::IsEvTimeTOF, + pidflags::IsEvTimeT0AC, + pidflags::IsEvTimeTOFT0AC); + +namespace pidtofsignal +{ +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 + +DECLARE_SOA_TABLE(TOFSignal, "AOD", "TOFSignal", //! Table of the TOF signal + pidtofsignal::TOFSignal, + pidtofsignal::EventCollisionTime); + +namespace pidtofevtime +{ +DECLARE_SOA_COLUMN(TOFEvTime, tofEvTime, float); //! event time for TOF signal. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C +DECLARE_SOA_COLUMN(TOFEvTimeErr, tofEvTimeErr, float); //! event time error for TOF. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C +} // namespace pidtofevtime + +DECLARE_SOA_TABLE(TOFEvTime, "AOD", "TOFEvTime", //! Table of the TOF event time. One entry per track. + pidtofevtime::TOFEvTime, + pidtofevtime::TOFEvTimeErr); + namespace pidtof { // Expected signals @@ -397,69 +457,15 @@ DECLARE_SOA_TABLE(pidTOFHe, "AOD", "pidTOFHe", //! Table of the TOF response wit DECLARE_SOA_TABLE(pidTOFAl, "AOD", "pidTOFAl", //! Table of the TOF response with binned Nsigma for alpha pidtof_tiny::TOFNSigmaStoreAl, pidtof_tiny::TOFNSigmaAl); -// Extra tables -namespace pidflags -{ - -namespace enums -{ -enum PIDFlags : uint8_t { - EvTimeUndef = 0x0, // Event collision not set, corresponding to the LHC Fill event time - EvTimeTOF = 0x1, // Event collision time from TOF - EvTimeT0AC = 0x2, // Event collision time from the FT0AC - EvTimeTOFT0AC = 0x4 // Event collision time from the TOF and FT0AC -}; -} - -DECLARE_SOA_COLUMN(GoodTOFMatch, goodTOFMatch, bool); //! Bool for the TOF PID information on the single track information -DECLARE_SOA_COLUMN(TOFFlags, tofFlags, uint8_t); //! Flag for the complementary TOF PID information for the event time -DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeDefined, isEvTimeDefined, //! True if the Event Time was computed with any method i.e. there is a usable event time - [](uint8_t flags) -> bool { return (flags > 0); }); -DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeTOF, isEvTimeTOF, //! True if the Event Time was computed with the TOF - [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeTOF) == enums::PIDFlags::EvTimeTOF; }); -DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeT0AC, isEvTimeT0AC, //! True if the Event Time was computed with the T0AC - [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeT0AC) == enums::PIDFlags::EvTimeT0AC; }); -DECLARE_SOA_DYNAMIC_COLUMN(IsEvTimeTOFT0AC, isEvTimeTOFT0AC, //! True if the Event Time was computed with the TOF and T0AC - [](uint8_t flags) -> bool { return (flags & enums::PIDFlags::EvTimeTOFT0AC) == enums::PIDFlags::EvTimeTOFT0AC; }); - -} // namespace pidflags - -DECLARE_SOA_TABLE(pidTOFFlags, "AOD", "pidTOFFlags", //! Table of the flags for TOF signal quality on the track level - pidflags::GoodTOFMatch); - -DECLARE_SOA_TABLE(pidEvTimeFlags, "AOD", "pidEvTimeFlags", //! Table of the PID flags for the event time tables - pidflags::TOFFlags, - pidflags::IsEvTimeDefined, - pidflags::IsEvTimeTOF, - pidflags::IsEvTimeT0AC, - pidflags::IsEvTimeTOFT0AC); - -namespace pidtofsignal -{ -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 - -DECLARE_SOA_TABLE(TOFSignal, "AOD", "TOFSignal", //! Table of the TOF signal - pidtofsignal::TOFSignal, - pidtofsignal::EventCollisionTime); - -namespace pidtofevtime -{ -DECLARE_SOA_COLUMN(TOFEvTime, tofEvTime, float); //! event time for TOF signal. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C -DECLARE_SOA_COLUMN(TOFEvTimeErr, tofEvTimeErr, float); //! event time error for TOF. Can be obtained via a combination of detectors e.g. TOF, FT0A, FT0C -} // namespace pidtofevtime - -DECLARE_SOA_TABLE(TOFEvTime, "AOD", "TOFEvTime", //! Table of the TOF event time. One entry per track. - pidtofevtime::TOFEvTime, - pidtofevtime::TOFEvTimeErr); - namespace pidtofbeta { DECLARE_SOA_COLUMN(Beta, beta, float); //! TOF beta DECLARE_SOA_COLUMN(BetaError, betaerror, float); //! Uncertainty on the TOF beta +// Dynamic column, i.e. the future +DECLARE_SOA_DYNAMIC_COLUMN(TOFBetaImp, tofBeta, //! TOF Beta value + [](const float length, const float tofSignal, const float collisionTime) -> float { + return o2::pid::tof::Beta::GetBeta(length, tofSignal, collisionTime); + }); // DECLARE_SOA_COLUMN(ExpBetaEl, expbetael, float); //! Expected beta of electron DECLARE_SOA_COLUMN(ExpBetaElError, expbetaelerror, float); //! Expected uncertainty on the beta of electron @@ -469,14 +475,24 @@ DECLARE_SOA_DYNAMIC_COLUMN(DiffBetaEl, diffbetael, //! Difference be [](float beta, float expbetael) -> float { return beta - expbetael; }); } // namespace pidtofbeta +using TOFBeta = pidtofbeta::TOFBetaImp; + DECLARE_SOA_TABLE(pidTOFbeta, "AOD", "pidTOFbeta", //! Table of the TOF beta pidtofbeta::Beta, pidtofbeta::BetaError); namespace pidtofmass { DECLARE_SOA_COLUMN(TOFMass, mass, float); //! TOF mass +// Dynamic column, i.e. the future +DECLARE_SOA_DYNAMIC_COLUMN(TOFMassImp, tofMass, //! TOF Mass value + [](const float length, const float tofSignal, const float collisionTime, const float momentum) -> float { + const float beta = o2::pid::tof::Beta::GetBeta(length, tofSignal, collisionTime); + return o2::pid::tof::TOFMass::GetTOFMass(momentum, beta); + }); } // namespace pidtofmass +using TOFMass = pidtofmass::TOFMassImp; + DECLARE_SOA_TABLE(pidTOFmass, "AOD", "pidTOFmass", //! Table of the TOF mass pidtofmass::TOFMass); diff --git a/DPG/Tasks/AOTTrack/PID/TOF/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/TOF/CMakeLists.txt index f4f799d4f5b..87af80a68dd 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/CMakeLists.txt +++ b/DPG/Tasks/AOTTrack/PID/TOF/CMakeLists.txt @@ -20,6 +20,11 @@ o2physics_add_dpl_workflow(pid-tof-qa-beta PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(pid-tof-qa-beta-imp + SOURCES qaPIDTOFBetaImp.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(pid-tof-qa-mc SOURCES qaPIDTOFMC.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBetaImp.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBetaImp.cxx new file mode 100644 index 00000000000..f503ab1d92d --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFBetaImp.cxx @@ -0,0 +1,426 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file qaPIDTOFBetaImp.cxx +/// \author Nicolò Jacazio nicolo.jacazio@cern.ch +/// \brief Task to produce the TOF QA plots for Beta. Version using dynamic columns. Interim solution for test and benchmarking +/// + +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Framework/HistogramRegistry.h" +#include "Framework/StaticFor.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/TableProducer/PID/pidTOFBase.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// Task to produce the TOF Beta QA plots +struct tofPidBetaQaImp { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable logAxis{"logAxis", 0, "Flag to use a log momentum axis"}; + Configurable nBinsP{"nBinsP", 400, "Number of bins for the momentum"}; + Configurable minP{"minP", 0.1f, "Minimum momentum in range"}; + Configurable maxP{"maxP", 5.f, "Maximum momentum in range"}; + Configurable applyEvSel{"applyEvSel", 2, "Flag to apply event selection cut: 0 -> no event selection, 1 -> Run 2 event selection, 2 -> Run 3 event selection"}; + Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + Configurable splitTrdTracks{"splitTrdTracks", false, "Flag to fill histograms for tracks with TRD match"}; + Configurable splitSignalPerCharge{"splitSignalPerCharge", true, "Split the signal per charge (reduces memory footprint if off)"}; + Configurable splitSignalPerEvTime{"splitSignalPerEvTime", true, "Split the signal per event time (reduces memory footprint if off)"}; + Configurable lastTrdLayerForTrdMatch{"lastTrdLayerForTrdMatch", 5, "Last TRD layer to consider for TRD match"}; + + ConfigurableAxis tofMassBins{"tofMassBins", {1000, 0, 3.f}, "Binning in the TOF mass plot"}; + ConfigurableAxis tofBetaBins{"tofBetaBins", {4000, 0, 2.f}, "Binning in the TOF beta plot"}; + ConfigurableAxis trackLengthBins{"trackLengthBins", {100, 0, 1000.f}, "Binning in track length plot"}; + Configurable requireGoodMatchTracks{"requireGoodMatchTracks", false, "Require good match tracks"}; + Configurable mMaxTOFChi2{"maxTOFChi2", 3.f, "Maximum TOF Chi2"}; + Configurable mEtaWindow{"etaWindow", 0.8f, "Window in eta for tracks"}; + + void init(o2::framework::InitContext&) + { + const AxisSpec vtxZAxis{100, -20, 20, "Vtx_{z} (cm)"}; + const AxisSpec tofAxis{10000, 0, 2e6, "TOF Signal"}; + const AxisSpec betaAxis{tofBetaBins, "TOF #beta"}; + const AxisSpec massAxis{tofMassBins, "TOF mass (GeV/#it{c}^{2})"}; + const AxisSpec trdAxis{10, -0.5, 9.5, "Last TRD cluster"}; + const AxisSpec etaAxis{100, -2, 2, "#it{#eta}"}; + const AxisSpec colTimeAxis{100, -2000, 2000, "Collision time (ps)"}; + const AxisSpec lAxis{trackLengthBins, "Track length (cm)"}; + const AxisSpec tofChi2Axis{1000, 0, 20, "TOF residual (cm)"}; + const AxisSpec ptResoAxis{100, 0, 0.1, "#sigma_{#it{p}_{T}}"}; + const AxisSpec pAxisPosNeg{2 * nBinsP, -maxP, maxP, "signed #it{p} (GeV/#it{c})"}; + AxisSpec ptAxis{nBinsP, minP, maxP, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pAxis{nBinsP, minP, maxP, "#it{p} (GeV/#it{c})"}; + if (logAxis) { + ptAxis.makeLogarithmic(); + pAxis.makeLogarithmic(); + } + + // Event properties + histos.add("event/tofsignal", "", HistType::kTH2F, {pAxis, tofAxis}); + const AxisSpec chargeAxis{2, -2.f, 2.f, "Charge"}; + + // TOF mass + if (splitSignalPerCharge) { + histos.add("tofmass/inclusive", "", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/EvTimeTOF", "Ev. Time TOF", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + } + if (splitTrdTracks) { + histos.add("tofmass/trd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + } + histos.add("tofmass/notrd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + histos.add("tofmass/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxis, massAxis, chargeAxis}); + } + } + } else { + histos.add("tofmass/inclusive", "", HistType::kTH2F, {pAxis, massAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/EvTimeTOF", "Ev. Time TOF", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH2F, {pAxis, massAxis}); + } + if (splitTrdTracks) { + histos.add("tofmass/trd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + } + histos.add("tofmass/notrd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + if (splitSignalPerEvTime) { + histos.add("tofmass/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + histos.add("tofmass/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxis, massAxis}); + } + } + } + + // TOF beta + if (splitSignalPerCharge) { + histos.add("tofbeta/inclusive", "", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/EvTimeTOF", "Ev. Time TOF", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + } + if (splitTrdTracks) { + histos.add("tofbeta/trd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + } + histos.add("tofbeta/notrd/inclusive", "(hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + histos.add("tofbeta/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH3F, {pAxis, betaAxis, chargeAxis}); + } + } + } else { + histos.add("tofbeta/inclusive", "", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/EvTimeTOF", "Ev. Time TOF", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/EvTimeTOFOnly", "Ev. Time TOF Only", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/EvTimeT0AC", "Ev. Time T0AC", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/EvTimeT0ACOnly", "Ev. Time T0AC Only", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + } + if (splitTrdTracks) { + histos.add("tofbeta/trd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/trd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/trd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/trd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/trd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + } + histos.add("tofbeta/notrd/inclusive", "(hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + if (splitSignalPerEvTime) { + histos.add("tofbeta/notrd/EvTimeTOF", "Ev. Time TOF (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/notrd/EvTimeTOFOnly", "Ev. Time TOF Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/notrd/EvTimeT0AC", "Ev. Time T0AC (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + histos.add("tofbeta/notrd/EvTimeT0ACOnly", "Ev. Time T0AC Only (hasTRD)", HistType::kTH2F, {pAxisPosNeg, betaAxis}); + } + } + } + + histos.add("event/tofchi2", "", HistType::kTH1F, {tofChi2Axis}); + histos.add("event/eta", "", HistType::kTH1F, {etaAxis}); + histos.add("event/length", "", HistType::kTH1F, {lAxis}); + if (splitTrdTracks) { + histos.add("event/trd/length", "", HistType::kTH2F, {lAxis, trdAxis}); + histos.add("event/notrd/length", "", HistType::kTH1F, {lAxis}); + } + histos.add("event/pt", "", HistType::kTH1F, {ptAxis}); + histos.add("event/p", "", HistType::kTH1F, {pAxis}); + auto h = histos.add("event/evsel", "", kTH1F, {{10, 0.5, 10.5, "Ev. Sel."}}); + h->GetXaxis()->SetBinLabel(1, "Events read"); + h->GetXaxis()->SetBinLabel(2, "Passed ev. sel."); + h->GetXaxis()->SetBinLabel(3, "Passed vtx Z"); + + h = histos.add("event/trackselection", "", kTH1F, {{10, 0.5, 10.5, "Selection passed"}}); + h->GetXaxis()->SetBinLabel(1, "Tracks read"); + h->GetXaxis()->SetBinLabel(2, "hasTOF"); + h->GetXaxis()->SetBinLabel(3, "isGlobalTrack"); + h->GetXaxis()->SetBinLabel(4, TString::Format("TOF chi2 < %.2f", mMaxTOFChi2.value)); + } + + Filter eventFilter = (applyEvSel.node() == 0) || + ((applyEvSel.node() == 1) && (o2::aod::evsel::sel7 == true)) || + ((applyEvSel.node() == 2) && (o2::aod::evsel::sel8 == true)); + Filter trackFilter = (trackSelection.node() == 0) || + ((trackSelection.node() == 1) && requireGlobalTrackInFilter()) || + ((trackSelection.node() == 2) && requireGlobalTrackWoPtEtaInFilter()) || + ((trackSelection.node() == 3) && requireGlobalTrackWoDCAInFilter()) || + ((trackSelection.node() == 4) && requireQualityTracksInFilter()) || + ((trackSelection.node() == 5) && requireInAcceptanceTracksInFilter()); + Filter etaFilter = (nabs(o2::aod::track::eta) < mEtaWindow); + + using CollisionCandidate = soa::Filtered>::iterator; + using TrackCandidates = soa::Join; + void process(CollisionCandidate const& collision, + soa::Filtered const& tracks) + { + + auto tracksWithPid = soa::Attach, aod::TOFMass, aod::TOFBeta>(tracks); + histos.fill(HIST("event/evsel"), 1); + if (applyEvSel == 1) { + if (!collision.sel7()) { + return; + } + } else if (applyEvSel == 2) { + if (!collision.sel8()) { + return; + } + } + + histos.fill(HIST("event/evsel"), 2); + + if (std::abs(collision.posZ()) > 10.f) { + return; + } + + histos.fill(HIST("event/evsel"), 3); + for (auto const& t : tracks) { + auto track = tracksWithPid.iteratorAt(t.globalIndex() - tracksWithPid.iteratorAt(0).globalIndex()); + // Check consistency + if (track.hasTOF() != t.hasTOF()) { + LOG(fatal) << "Mismatch in TOF availability!"; + } + if (track.pt() != t.pt()) { + LOG(fatal) << "Mismatch in pt!"; + } + histos.fill(HIST("event/trackselection"), 1.f); + if (!track.hasTOF()) { // Skipping tracks without TOF + continue; + } + histos.fill(HIST("event/trackselection"), 2.f); + if (!track.isGlobalTrack()) { + continue; + } + histos.fill(HIST("event/trackselection"), 3.f); + if (track.tofChi2() > mMaxTOFChi2) { // Skipping tracks with large Chi2 + continue; + } + histos.fill(HIST("event/trackselection"), 4.f); + const float tofMass = track.tofMass(); + const float tofBeta = track.tofBeta(); + if (splitSignalPerCharge) { + histos.fill(HIST("tofmass/inclusive"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/inclusive"), track.p(), tofBeta, track.sign()); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/EvTimeTOF"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/EvTimeTOF"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/EvTimeTOFOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/EvTimeTOFOnly"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/EvTimeT0AC"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/EvTimeT0AC"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/EvTimeT0ACOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/EvTimeT0ACOnly"), track.p(), tofBeta, track.sign()); + } + } + } else { + histos.fill(HIST("tofmass/inclusive"), track.p(), tofMass); + histos.fill(HIST("tofbeta/inclusive"), track.p(), tofBeta); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/EvTimeTOF"), track.p(), tofMass); + histos.fill(HIST("tofbeta/EvTimeTOF"), track.p(), tofBeta); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/EvTimeTOFOnly"), track.p(), tofMass); + histos.fill(HIST("tofbeta/EvTimeTOFOnly"), track.p(), tofBeta); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/EvTimeT0AC"), track.p(), tofMass); + histos.fill(HIST("tofbeta/EvTimeT0AC"), track.p(), tofBeta); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/EvTimeT0ACOnly"), track.p(), tofMass); + histos.fill(HIST("tofbeta/EvTimeT0ACOnly"), track.p(), tofBeta); + } + } + } + histos.fill(HIST("event/length"), track.length()); + histos.fill(HIST("event/tofchi2"), track.tofChi2()); + histos.fill(HIST("event/eta"), track.eta()); + histos.fill(HIST("event/tofsignal"), track.p(), track.tofSignal()); + histos.fill(HIST("event/pt"), track.pt()); + histos.fill(HIST("event/p"), track.p()); + + if (!splitTrdTracks) { // If splitting of TRD tracks is not enabled, skip + continue; + } + + if (!track.hasTRD()) { + histos.fill(HIST("event/notrd/length"), track.length()); + if (splitSignalPerCharge) { + histos.fill(HIST("tofmass/notrd/inclusive"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/notrd/inclusive"), track.p(), tofBeta, track.sign()); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/notrd/EvTimeTOF"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/notrd/EvTimeTOF"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/notrd/EvTimeTOFOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/notrd/EvTimeTOFOnly"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/notrd/EvTimeT0AC"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/notrd/EvTimeT0AC"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/notrd/EvTimeT0ACOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/notrd/EvTimeT0ACOnly"), track.p(), tofBeta, track.sign()); + } + } + } else { + const float signedp = track.p() * track.sign(); + histos.fill(HIST("tofmass/notrd/inclusive"), signedp, tofMass); + histos.fill(HIST("tofbeta/notrd/inclusive"), signedp, tofBeta); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/notrd/EvTimeTOF"), signedp, tofMass); + histos.fill(HIST("tofbeta/notrd/EvTimeTOF"), signedp, tofBeta); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/notrd/EvTimeTOFOnly"), signedp, tofMass); + histos.fill(HIST("tofbeta/notrd/EvTimeTOFOnly"), signedp, tofBeta); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/notrd/EvTimeT0AC"), signedp, tofMass); + histos.fill(HIST("tofbeta/notrd/EvTimeT0AC"), signedp, tofBeta); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/notrd/EvTimeT0ACOnly"), signedp, tofMass); + histos.fill(HIST("tofbeta/notrd/EvTimeT0ACOnly"), signedp, tofBeta); + } + } + } + } else { + + int lastLayer = 0; + for (int l = 7; l >= 0; l--) { + if (track.trdPattern() & (1 << l)) { + lastLayer = l; + break; + } + } + + histos.fill(HIST("event/trd/length"), track.length(), lastLayer); + if (lastLayer < lastTrdLayerForTrdMatch) { + continue; + } + if (splitSignalPerCharge) { + histos.fill(HIST("tofmass/trd/inclusive"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/trd/inclusive"), track.p(), tofBeta, track.sign()); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/trd/EvTimeTOF"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/trd/EvTimeTOF"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/trd/EvTimeTOFOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/trd/EvTimeTOFOnly"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/trd/EvTimeT0AC"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/trd/EvTimeT0AC"), track.p(), tofBeta, track.sign()); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/trd/EvTimeT0ACOnly"), track.p(), tofMass, track.sign()); + histos.fill(HIST("tofbeta/trd/EvTimeT0ACOnly"), track.p(), tofBeta, track.sign()); + } + } + } else { + const float signedp = track.p() * track.sign(); + histos.fill(HIST("tofmass/trd/inclusive"), signedp, tofMass); + histos.fill(HIST("tofbeta/trd/inclusive"), signedp, tofBeta); + if (splitSignalPerEvTime) { + if (track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/trd/EvTimeTOF"), signedp, tofMass); + histos.fill(HIST("tofbeta/trd/EvTimeTOF"), signedp, tofBeta); + } + if (track.isEvTimeTOF() && !track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/trd/EvTimeTOFOnly"), signedp, tofMass); + histos.fill(HIST("tofbeta/trd/EvTimeTOFOnly"), signedp, tofBeta); + } + if (track.isEvTimeT0AC()) { + histos.fill(HIST("tofmass/trd/EvTimeT0AC"), signedp, tofMass); + histos.fill(HIST("tofbeta/trd/EvTimeT0AC"), signedp, tofBeta); + } + if (track.isEvTimeT0AC() && !track.isEvTimeTOF()) { + histos.fill(HIST("tofmass/trd/EvTimeT0ACOnly"), signedp, tofMass); + histos.fill(HIST("tofbeta/trd/EvTimeT0ACOnly"), signedp, tofBeta); + } + } + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; }