diff --git a/PWGCF/CMakeLists.txt b/PWGCF/CMakeLists.txt index f31b23ad6a3..23afeaf6d0d 100644 --- a/PWGCF/CMakeLists.txt +++ b/PWGCF/CMakeLists.txt @@ -17,4 +17,5 @@ add_subdirectory(FemtoWorld) add_subdirectory(MultiparticleCorrelations) add_subdirectory(Tasks) add_subdirectory(TableProducer) +add_subdirectory(Tutorial) diff --git a/PWGCF/Tutorial/CFTutorialTask0.cxx b/PWGCF/Tutorial/CFTutorialTask0.cxx new file mode 100644 index 00000000000..3de52379610 --- /dev/null +++ b/PWGCF/Tutorial/CFTutorialTask0.cxx @@ -0,0 +1,68 @@ +// 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. + +/// \author Luca Barioglio + +// O2 includes +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Example task illustrating how to create histograms and fill them with basic information. +// A basic event selection is applied. + +struct CFTutorialTask0 { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Equivalent of the AliRoot task UserCreateOutputObjects + void init(o2::framework::InitContext&) + { + // Define your axes + // Constant bin width axis + AxisSpec vtxZAxis = {100, -20, 20}; + // Variable bin width axis + std::vector ptBinning = {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.}; + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + + // Add histograms to histogram manager (as in the output object of in AliPhysics) + histos.add("hZvtx_before_sel", ";Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hZvtx_after_sel", ";Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hP", ";#it{p} (GeV/#it{c})", kTH1F, {{35, 0.5, 4.}}); + histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + } + + // Equivalent of the AliRoot task UserExec + void process(aod::Collision const& coll, aod::Tracks const& inputTracks) + { + // Performing the event selection + histos.fill(HIST("hZvtx_before_sel"), coll.posZ()); + if (fabs(coll.posZ()) > 10.f) { + return; + } + histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); + + for (auto track : inputTracks) { // Loop over tracks + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Equivalent to the AddTask in AliPhysics + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/Tutorial/CFTutorialTask1.cxx b/PWGCF/Tutorial/CFTutorialTask1.cxx new file mode 100644 index 00000000000..f79eb1871c2 --- /dev/null +++ b/PWGCF/Tutorial/CFTutorialTask1.cxx @@ -0,0 +1,88 @@ +// 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. + +/// \author Luca Barioglio + +// O2 includes +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 1 +// Example task illustrating how to acess information from different tables + +namespace o2::aod +{ +using MyCollisions = soa::Join; +using MyTracks = soa::Join; +using MyCollision = MyCollisions::iterator; +using MyTrack = MyTracks::iterator; +} // namespace o2::aod + +struct CFTutorialTask1 { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Equivalent of the AliRoot task UserCreateOutputObjects + void init(o2::framework::InitContext&) + { + // Define your axes + // Constant bin width axis + AxisSpec vtxZAxis = {100, -20, 20}; + // Variable bin width axis + std::vector ptBinning = {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.}; + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + + // Add histograms to histogram manager (as in the output object of in AliPhysics) + histos.add("hZvtx_before_sel", ";Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hZvtx_after_sel", ";Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hP", ";#it{p} (GeV/#it{c})", kTH1F, {{35, 0.5, 4.}}); + histos.add("hEta", ";#it{p} (GeV/#it{c})", kTH1F, {{100, -1.5, 1.5}}); + histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hNsigmaTPCP", ";#it{p} (GeV/#it{c}); n#sigma_{TPC}^{p}", kTH2F, {{35, 0.5, 4.}, {100, -5., 5.}}); + } + + // Equivalent of the AliRoot task UserExec + void process(aod::MyCollision const& coll, aod::MyTracks const& inputTracks) + { + // Performing the event selection + histos.fill(HIST("hZvtx_before_sel"), coll.posZ()); + if (fabs(coll.posZ()) > 10.f) { + return; + } + histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); + + for (auto track : inputTracks) { // Loop over tracks + if (fabs(track.eta()) > 0.8) { + continue; + } + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + histos.fill(HIST("hNsigmaTPCP"), track.p(), track.tpcNSigmaPr()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Equivalent to the AddTask in AliPhysics + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/Tutorial/CFTutorialTask2.cxx b/PWGCF/Tutorial/CFTutorialTask2.cxx new file mode 100644 index 00000000000..bf40ce17353 --- /dev/null +++ b/PWGCF/Tutorial/CFTutorialTask2.cxx @@ -0,0 +1,100 @@ +// 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. + +/// \author Luca Barioglio + +// O2 includes +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 2 +// Example task illustrating how to use Configurables and Filters + +namespace o2::aod +{ +using MyCollisions = soa::Join; +using MyTracks = soa::Join; +using MyCollision = MyCollisions::iterator; +using MyTrack = MyTracks::iterator; +} // namespace o2::aod + +struct CFTutorialTask2 { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Defining configurables + Configurable ConfZvtxCut{"ConfZvtxCut", 10, "Z vtx cut"}; + Configurable ConfEtaCut{"ConfEtaCut", 0.8, "Pseudorapidity cut"}; + Configurable ConfMaxPtCut{"ConfMaxPtCut", 3.0, "Max Pt cut"}; + Configurable ConfMinPtCut{"ConfMinPtCut", 0.5, "Min Pt cut"}; + Configurable ConfMinNSigmaTPCCut{"ConfMinNSigmaTPCCut", 3, "N-sigma TPC cut"}; + + // Defining filters + Filter collisionFilter = (nabs(aod::collision::posZ) < ConfZvtxCut); + Filter trackFilter = (nabs(aod::track::eta) < ConfEtaCut) && (aod::track::pt > ConfMinPtCut) && (aod::track::pt < ConfMaxPtCut); + + // Applying filters + using MyFilteredCollisions = soa::Filtered; + using MyFilteredCollision = MyFilteredCollisions::iterator; + using MyFilteredTracks = soa::Filtered; + using MyFilteredTrack = MyFilteredTracks::iterator; + + // Equivalent of the AliRoot task UserCreateOutputObjects + void init(o2::framework::InitContext&) + { + // Define your axes + // Constant bin width axis + AxisSpec vtxZAxis = {100, -20, 20}; + // Variable bin width axis + std::vector ptBinning = {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.}; + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + + // Add histograms to histogram manager (as in the output object of in AliPhysics) + histos.add("hZvtx", ";Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hP", ";#it{p} (GeV/#it{c})", kTH1F, {{35, 0.5, 4.}}); + histos.add("hEta", ";#it{p} (GeV/#it{c})", kTH1F, {{100, -1.5, 1.5}}); + histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hNsigmaTPCP", ";#it{p} (GeV/#it{c}); n#sigma_{TPC}^{p}", kTH2F, {{35, 0.5, 4.}, {100, -5., 5.}}); + } + + // Equivalent of the AliRoot task UserExec + void process(MyFilteredCollision const& coll, MyFilteredTracks const& inputTracks) + { + histos.fill(HIST("hZvtx"), coll.posZ()); + + for (auto track : inputTracks) { + if (fabs(track.tpcNSigmaPr()) > ConfMinNSigmaTPCCut) { // TPCNSigmaPr is a dynamic column and it is not compatible with Filters + continue; + } + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + histos.fill(HIST("hEta"), track.eta()); + histos.fill(HIST("hNsigmaTPCP"), track.p(), track.tpcNSigmaPr()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Equivalent to the AddTask in AliPhysics + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/Tutorial/CFTutorialTask3.cxx b/PWGCF/Tutorial/CFTutorialTask3.cxx new file mode 100644 index 00000000000..3735facf3d2 --- /dev/null +++ b/PWGCF/Tutorial/CFTutorialTask3.cxx @@ -0,0 +1,112 @@ +// 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. + +/// \author Luca Barioglio + +// O2 includes +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 2 +// Example task illustrating how to create and use partitions + +namespace o2::aod +{ +using MyCollisions = soa::Join; +using MyTracks = soa::Join; +using MyCollision = MyCollisions::iterator; +using MyTrack = MyTracks::iterator; +} // namespace o2::aod + +struct CFTutorialTask3 { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Defining configurables + Configurable ConfZvtxCut{"ConfZvtxCut", 10, "Z vtx cut"}; + Configurable ConfEtaCut{"ConfEtaCut", 0.8, "Pseudorapidity cut"}; + Configurable ConfMaxPtCut{"ConfMaxPtCut", 3.0, "Max Pt cut"}; + Configurable ConfMinPtCut{"ConfMinPtCut", 0.5, "Min Pt cut"}; + Configurable ConfMinNSigmaTPCCut{"ConfMinNSigmaTPCCut", 3., "N-sigma TPC cut"}; + Configurable ConfChargeCut{"ConfChargeCut", 0., "N-sigma TPC cut"}; + + // Defining filters + Filter collisionFilter = (nabs(aod::collision::posZ) < ConfZvtxCut); + Filter trackFilter = (nabs(aod::track::eta) < ConfEtaCut) && (aod::track::pt > ConfMinPtCut) && (aod::track::pt < ConfMaxPtCut); + + // Applying filters + using MyFilteredCollisions = soa::Filtered; + using MyFilteredCollision = MyFilteredCollisions::iterator; + + Partition positive = (nabs(aod::track::eta) < ConfEtaCut) && (aod::track::pt > ConfMinPtCut) && (aod::track::pt < ConfMaxPtCut) && (aod::track::signed1Pt > ConfChargeCut); + Partition negative = (nabs(aod::track::eta) < ConfEtaCut) && (aod::track::pt > ConfMinPtCut) && (aod::track::pt < ConfMaxPtCut) && (aod::track::signed1Pt < ConfChargeCut); + + // Equivalent of the AliRoot task UserCreateOutputObjects + void init(o2::framework::InitContext&) + { + // Define your axes + // Constant bin width axis + AxisSpec vtxZAxis = {100, -20, 20}; + // Variable bin width axis + std::vector ptBinning = {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.}; + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + + // Add histograms to histogram manager (as in the output object of in AliPhysics) + histos.add("hZvtx", ";Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hP", ";#it{p} (GeV/#it{c})", kTH1F, {{35, 0.5, 4.}}); + histos.add("hEta", ";#it{p} (GeV/#it{c})", kTH1F, {{100, -1.5, 1.5}}); + histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hNsigmaTPCP", ";#it{p} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{35, 0.5, 4.}, {100, -5., 5.}}); + histos.add("hChargePos", ";z;", kTH1F, {{3, -1.5, 1.5}}); + histos.add("hChargeNeg", ";z;", kTH1F, {{3, -1.5, 1.5}}); + } + + // Equivalent of the AliRoot task UserExec + void process(MyFilteredCollision const& coll, o2::aod::MyTracks const& tracks) + { + auto groupPositive = positive->sliceByCached(aod::track::collisionId, coll.globalIndex()); + auto groupNegative = negative->sliceByCached(aod::track::collisionId, coll.globalIndex()); + histos.fill(HIST("hZvtx"), coll.posZ()); + + for (auto track : groupPositive) { + histos.fill(HIST("hChargePos"), track.sign()); + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + histos.fill(HIST("hEta"), track.eta()); + histos.fill(HIST("hNsigmaTPCP"), track.p(), track.tpcNSigmaPi()); + } + + for (auto track : groupNegative) { + histos.fill(HIST("hChargeNeg"), track.sign()); + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + histos.fill(HIST("hEta"), track.eta()); + histos.fill(HIST("hNsigmaTPCP"), track.p(), track.tpcNSigmaPi()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Equivalent to the AddTask in AliPhysics + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/Tutorial/CFTutorialTask4.cxx b/PWGCF/Tutorial/CFTutorialTask4.cxx new file mode 100644 index 00000000000..64f8a551f10 --- /dev/null +++ b/PWGCF/Tutorial/CFTutorialTask4.cxx @@ -0,0 +1,130 @@ +// 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. + +/// \author Luca Barioglio + +// O2 includes +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "CommonConstants/PhysicsConstants.h" + +#include "TLorentzVector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 2 +// Example task illustrating how to mix elements of different partitions + +namespace o2::aod +{ +using MyCollisions = soa::Join; +using MyTracks = soa::Join; +using MyCollision = MyCollisions::iterator; +using MyTrack = MyTracks::iterator; +} // namespace o2::aod + +struct CFTutorialTask4 { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Defining configurables + Configurable ConfZvtxCut{"ConfZvtxCut", 10, "Z vtx cut"}; + Configurable ConfEtaCut{"ConfEtaCut", 0.8, "Pseudorapidity cut"}; + Configurable ConfMaxPtCut{"ConfMaxPtCut", 3.0, "Max Pt cut"}; + Configurable ConfMinPtCut{"ConfMinPtCut", 0.5, "Min Pt cut"}; + Configurable ConfMinNSigmaTPCCut{"ConfMinNSigmaTPCCut", 3., "N-sigma TPC cut"}; + Configurable ConfChargeCut{"ConfChargeCut", 0., "N-sigma TPC cut"}; + + // Defining filters + Filter collisionFilter = (nabs(aod::collision::posZ) < ConfZvtxCut); + Filter trackFilter = (nabs(aod::track::eta) < ConfEtaCut) && (aod::track::pt > ConfMinPtCut) && (aod::track::pt < ConfMaxPtCut); + + // Applying filters + using MyFilteredCollisions = soa::Filtered; + using MyFilteredCollision = MyFilteredCollisions::iterator; + + Partition positive = (nabs(aod::track::eta) < ConfEtaCut) && (aod::track::pt > ConfMinPtCut) && (aod::track::pt < ConfMaxPtCut) && (aod::track::signed1Pt > ConfChargeCut); + Partition negative = (nabs(aod::track::eta) < ConfEtaCut) && (aod::track::pt > ConfMinPtCut) && (aod::track::pt < ConfMaxPtCut) && (aod::track::signed1Pt < ConfChargeCut); + + // Equivalent of the AliRoot task UserCreateOutputObjects + void init(o2::framework::InitContext&) + { + // Define your axes + // Constant bin width axis + AxisSpec vtxZAxis = {100, -20, 20}; + // Variable bin width axis + std::vector ptBinning = {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.}; + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + + // Add histograms to histogram manager (as in the output object of in AliPhysics) + histos.add("hZvtx", ";Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hP", ";#it{p} (GeV/#it{c})", kTH1F, {{35, 0.5, 4.}}); + histos.add("hEta", ";#it{p} (GeV/#it{c})", kTH1F, {{100, -1.5, 1.5}}); + histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hNsigmaTPCP", ";#it{p} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{35, 0.5, 4.}, {100, -5., 5.}}); + histos.add("hChargePos", ";z;", kTH1F, {{3, -1.5, 1.5}}); + histos.add("hChargeNeg", ";z;", kTH1F, {{3, -1.5, 1.5}}); + histos.add("hInvariantMass", ";M_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2});", kTH1F, {{100, 0., 1.0}}); + } + + // Equivalent of the AliRoot task UserExec + void process(MyFilteredCollision const& coll, o2::aod::MyTracks const& tracks) + { + auto groupPositive = positive->sliceByCached(aod::track::collisionId, coll.globalIndex()); + auto groupNegative = negative->sliceByCached(aod::track::collisionId, coll.globalIndex()); + histos.fill(HIST("hZvtx"), coll.posZ()); + + for (auto track : groupPositive) { + histos.fill(HIST("hChargePos"), track.sign()); + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + histos.fill(HIST("hEta"), track.eta()); + histos.fill(HIST("hNsigmaTPCP"), track.p(), track.tpcNSigmaPi()); + } + + for (auto track : groupNegative) { + histos.fill(HIST("hChargeNeg"), track.sign()); + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + histos.fill(HIST("hEta"), track.eta()); + histos.fill(HIST("hNsigmaTPCP"), track.p(), track.tpcNSigmaPi()); + } + + for (auto& [pos, neg] : combinations(soa::CombinationsFullIndexPolicy(groupPositive, groupNegative))) { + if (fabs(pos.tpcNSigmaPi()) > 3 or fabs(neg.tpcNSigmaPi()) > 3) { + continue; + } + TLorentzVector posVec; + posVec.SetPtEtaPhiM(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassPionCharged); + TLorentzVector negVec; + negVec.SetPtEtaPhiM(neg.pt(), neg.eta(), neg.phi(), o2::constants::physics::MassPionCharged); + + TLorentzVector sumVec(posVec); + sumVec += negVec; + histos.fill(HIST("hInvariantMass"), sumVec.M()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Equivalent to the AddTask in AliPhysics + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/Tutorial/CFTutorialTask5.cxx b/PWGCF/Tutorial/CFTutorialTask5.cxx new file mode 100644 index 00000000000..a097786f953 --- /dev/null +++ b/PWGCF/Tutorial/CFTutorialTask5.cxx @@ -0,0 +1,190 @@ +// 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. + +/// \author Luca Barioglio + +// O2 includes +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponse.h" +#include "CommonConstants/PhysicsConstants.h" + +#include "TLorentzVector.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 2 +// Example task illustrating how to mix elements of different partitions and different events + process switches + +namespace o2::aod +{ +using MyCollisions = soa::Join; +using MyTracks = soa::Join; +using MyCollision = MyCollisions::iterator; +using MyTrack = MyTracks::iterator; +} // namespace o2::aod + +struct CFTutorialTask5 { + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Defining configurables + Configurable ConfZvtxCut{"ConfZvtxCut", 10, "Z vtx cut"}; + Configurable ConfEtaCut{"ConfEtaCut", 0.8, "Pseudorapidity cut"}; + Configurable ConfMaxPtCut{"ConfMaxPtCut", 3.0, "Max Pt cut"}; + Configurable ConfMinPtCut{"ConfMinPtCut", 0.5, "Min Pt cut"}; + Configurable ConfMinNSigmaTPCCut{"ConfMinNSigmaTPCCut", 3., "N-sigma TPC cut"}; + Configurable ConfChargeCut{"ConfChargeCut", 0., "N-sigma TPC cut"}; + + // Defining filters + Filter collisionFilter = (nabs(aod::collision::posZ) < ConfZvtxCut); + Filter trackFilter = (nabs(aod::track::eta) < ConfEtaCut) && (aod::track::pt > ConfMinPtCut) && (aod::track::pt < ConfMaxPtCut); + + // Applying filters + using MyFilteredCollisions = soa::Filtered; + using MyFilteredCollision = MyFilteredCollisions::iterator; + using MyFilteredTracks = soa::Filtered; + + Partition positive = aod::track::signed1Pt > ConfChargeCut; + Partition negative = aod::track::signed1Pt < ConfChargeCut; + + ConfigurableAxis ConfMultBins{"ConfMultBins", {VARIABLE_WIDTH, 0.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; + ConfigurableAxis ConfVtxBins{"ConfVtxBins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + + using BinningType = ColumnBinningPolicy; + + // Equivalent of the AliRoot task UserCreateOutputObjects + void init(o2::framework::InitContext&) + { + // Define your axes + // Constant bin width axis + AxisSpec vtxZAxis = {100, -20, 20}; + // Variable bin width axis + std::vector ptBinning = {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.}; + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + + // Add histograms to histogram manager (as in the output object of in AliPhysics) + histos.add("hZvtx", ";Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hP", ";#it{p} (GeV/#it{c})", kTH1F, {{35, 0.5, 4.}}); + histos.add("hEta", ";#it{p} (GeV/#it{c})", kTH1F, {{100, -1.5, 1.5}}); + histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + histos.add("hNsigmaTPCP", ";#it{p} (GeV/#it{c}); n#sigma_{TPC}^{#pi}", kTH2F, {{35, 0.5, 4.}, {100, -5., 5.}}); + histos.add("hChargePos", ";z;", kTH1F, {{3, -1.5, 1.5}}); + histos.add("hChargeNeg", ";z;", kTH1F, {{3, -1.5, 1.5}}); + histos.add("hInvariantMass", ";M_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2});", kTH1F, {{100, 0., 1.0}}); + histos.add("hInvariantMassMixed", ";M_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2});", kTH1F, {{100, 0., 1.0}}); + histos.add("hInvariantMassMixedInterface", ";M_{#pi^{+}#pi^{-}} (GeV/#it{c}^{2});", kTH1F, {{100, 0., 1.0}}); + } + + void processSame(MyFilteredCollision const& coll, MyFilteredTracks const& tracks) + { + auto groupPositive = positive->sliceByCached(aod::track::collisionId, coll.globalIndex()); + auto groupNegative = negative->sliceByCached(aod::track::collisionId, coll.globalIndex()); + histos.fill(HIST("hZvtx"), coll.posZ()); + + for (auto track : groupPositive) { + histos.fill(HIST("hChargePos"), track.sign()); + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + histos.fill(HIST("hEta"), track.eta()); + histos.fill(HIST("hNsigmaTPCP"), track.p(), track.tpcNSigmaPi()); + } + + for (auto track : groupNegative) { + histos.fill(HIST("hChargeNeg"), track.sign()); + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + histos.fill(HIST("hEta"), track.eta()); + histos.fill(HIST("hNsigmaTPCP"), track.p(), track.tpcNSigmaPi()); + } + + for (auto& [pos, neg] : combinations(soa::CombinationsFullIndexPolicy(groupPositive, groupNegative))) { + if (fabs(pos.tpcNSigmaPi()) > 3 or fabs(neg.tpcNSigmaPi()) > 3) { + continue; + } + TLorentzVector posVec; + posVec.SetPtEtaPhiM(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassPionCharged); + TLorentzVector negVec; + negVec.SetPtEtaPhiM(neg.pt(), neg.eta(), neg.phi(), o2::constants::physics::MassPionCharged); + + TLorentzVector sumVec(posVec); + sumVec += negVec; + histos.fill(HIST("hInvariantMass"), sumVec.M()); + } + } + PROCESS_SWITCH(CFTutorialTask5, processSame, "Enable processing same event", true); + + void processMixed(MyFilteredCollisions const& colls, MyFilteredTracks const& tracks) + { + BinningType colBinning{{ConfVtxBins, ConfMultBins}, true}; + for (auto& [collision1, collision2] : soa::selfCombinations(colBinning, 5, -1, colls, colls)) { + auto groupPositive = positive->sliceByCached(aod::track::collisionId, collision1.globalIndex()); + auto groupNegative = negative->sliceByCached(aod::track::collisionId, collision2.globalIndex()); + + for (auto& [pos, neg] : combinations(soa::CombinationsFullIndexPolicy(groupPositive, groupNegative))) { + if (fabs(pos.tpcNSigmaPi()) > 3 or fabs(neg.tpcNSigmaPi()) > 3) { + continue; + } + TLorentzVector posVec; + posVec.SetPtEtaPhiM(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassPionCharged); + TLorentzVector negVec; + negVec.SetPtEtaPhiM(neg.pt(), neg.eta(), neg.phi(), o2::constants::physics::MassPionCharged); + + TLorentzVector sumVec(posVec); + sumVec += negVec; + histos.fill(HIST("hInvariantMassMixed"), sumVec.M()); + } + } + } + PROCESS_SWITCH(CFTutorialTask5, processMixed, "Enable processing mixed event", true); + + void processMixedEventInterface(MyFilteredCollisions& colls, MyFilteredTracks& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + BinningType colBinning{{ConfVtxBins, ConfMultBins}, true}; + SameKindPair pair{colBinning, 5, -1, colls, tracksTuple}; + for (auto& [c1, tracks1, c2, tracks2] : pair) { + Partition groupPositive = aod::track::signed1Pt > ConfChargeCut; + groupPositive.bindTable(tracks1); + Partition groupNegative = aod::track::signed1Pt < ConfChargeCut; + groupNegative.bindTable(tracks2); + + for (auto& [pos, neg] : combinations(soa::CombinationsFullIndexPolicy(groupPositive, groupNegative))) { + if (fabs(pos.tpcNSigmaPi()) > 3 or fabs(neg.tpcNSigmaPi()) > 3) { + continue; + } + TLorentzVector posVec; + posVec.SetPtEtaPhiM(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassPionCharged); + TLorentzVector negVec; + negVec.SetPtEtaPhiM(neg.pt(), neg.eta(), neg.phi(), o2::constants::physics::MassPionCharged); + + TLorentzVector sumVec(posVec); + sumVec += negVec; + histos.fill(HIST("hInvariantMassMixedInterface"), sumVec.M()); + } + } + } + PROCESS_SWITCH(CFTutorialTask5, processMixedEventInterface, "Enable processing mixed event with standard mixing interface", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Equivalent to the AddTask in AliPhysics + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} diff --git a/PWGCF/Tutorial/CMakeLists.txt b/PWGCF/Tutorial/CMakeLists.txt new file mode 100644 index 00000000000..41947b55063 --- /dev/null +++ b/PWGCF/Tutorial/CMakeLists.txt @@ -0,0 +1,40 @@ +# 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. + +o2physics_add_dpl_workflow(cf-tutorial-0 + SOURCES CFTutorialTask0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(cf-tutorial-1 + SOURCES CFTutorialTask1.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(cf-tutorial-2 + SOURCES CFTutorialTask2.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(cf-tutorial-3 + SOURCES CFTutorialTask3.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(cf-tutorial-4 + SOURCES CFTutorialTask4.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(cf-tutorial-5 + SOURCES CFTutorialTask5.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/Tutorial/README.md b/PWGCF/Tutorial/README.md new file mode 100644 index 00000000000..2bbfe85b72f --- /dev/null +++ b/PWGCF/Tutorial/README.md @@ -0,0 +1,372 @@ +# O2Physics Tutorial for CF +Table of contents:
+1. [Prerequisites](#prerequisites)
+2. [Create your task](#create-your-task-in-o2physics)
+3. [Tutorial checkpoints](#tutorial-checkpoints)
+_________________ +_______________ +# Prerequisites +## How to install O2Physics Framework? +1. Build prerequisities for your operating system, configure aliBuild (but don't build packages!) - [here](https://alice-doc.github.io/alice-analysis-tutorial/building/custom.html).
+2. Get a GRID certificate - [here](https://alice-doc.github.io/alice-analysis-tutorial/start/cert.html)
+3. Follow instructions on [ALICE O2 documentation](https://aliceo2group.github.io/analysis-framework/docs/installing/) - Prepare your source code, check prerequisites, build and rebuild and check if everything works!
+ +Keep in mind that it might take quite a long time. +______________ +## How to update ALICE O2Physics? + +To update the software, you need to do the following:
+1. in `alice/alidist`, type `git pull`
+2. in `alice/O2Physics`, type `git pull --rebase`
+3. in `alice/`, type `aliBuild build O2Physics --defaults o2`. Here you can add `--debug` (or `-d`) for more information.
+ +You need to update it frequently, because O2 is constantly evolving. Keep in mind that it might take quite a long time. +_________ +## How to obtain data files for the analysis? + + +This tutorial is made and tested for pilot-beam data (reconstruction pass4). You can download the reference `AO2D.root` file from [here](https://alimonitor.cern.ch/catalogue/index.jsp?path=%2Falice%2Fdata%2F2021%2FOCT%2F505669%2Fapass4%2FAOD#/alice/data/2021/OCT/505669/apass4/AOD/006). We use file `006`. Be aware that due to the file size (around 400 MB), it could take a while. + + +A lot of Run 2 data converted into the Run 3 format can be found [here](https://alimonitor.cern.ch/trains/train.jsp?train_id=132). A detailed description of how to download converted Run 2 data is reported in the [offifial documentation](https://aliceo2group.github.io/analysis-framework/docs/download/) + +In summary, to download a bunch of data, do the following:
+1. scroll all the way down, choose the train number you are interested in and click on run number.
+2. A pop-up window appears: click on the **Test Results**.
+3. Scroll down, find the **Full Train** option and then click on **output**.
+4. Search for the `AO2D.root` file: click on it to download it.
+ +Be aware that it might take a while, because the size is around 1 GB file.
+ +Information about trains (job details) can be found [here](https://alimonitor.cern.ch/job_details.jsp). + +____________________________ +____________________________ +# Create your task in O2Physics + +There are many examples of simple introductory tasks in O2Physics that can be found in `O2Physics/Tutorials`. +All the information about how to write a task can be found in the [official documentation](https://aliceo2group.github.io/analysis-framework/docs/tutorials/). + +We hope that this hands-on tutorial will help you learning to write your analysis tasks starting from scratch. + +_________________ +## A O2Physics task in summary + +A task is a C++ `struct`, which must contain a `process` method. The `process` is the equivalent of what in `AliPhysics` was `UserExec`. It is used to access analysis objects, such as collisions, tracks, etc. + +In addition, the task can also have an `init` funcion, which is used to initialise analysis-objects such as histogram. It is the equivalent of `UserCreateOutputObjects` in AliPhysics. + +In the same source file where the `struct` is defined, one has to add a `defineDataProcessing` method, which is necessary to include the task to the workflow, assigning it a specific name. + +The task must be added to the `CMakeLists.txt` file in the same directory. For our tutorial, the first task has name `cf-tutorial-0` and it is defined in the source file `CFTutorialTask0.cxx`. The corresponfing lines in the `CMakeLists.txt` file are: + +``` +o2physics_add_dpl_workflow(cf-tutorial-0 + SOURCES CFTutorialTask0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) +``` +Everything will be (hopefully) clear in the hands-on session. + +_____________ +## How to build a task? + +The safest way to build your task is to use `aliBuild`, following the same instructions reported in the section [_How to update O2Physics?_](#how-to-update-alice-o2physics) + +If you want to save time and opt for a more advance method, read the following section + + **Advanced method** + +Go to `~/alice/sw/BUILD/O2Physics-latest-master/O2Physics`. +
If you have properly installed direnv, as soon as you enter a lot of text should appear and it should look like this: +

+ +![image](https://user-images.githubusercontent.com/87480906/162129203-4a4b833b-fefc-48c6-9229-908354cf0620.png) + +

+
+ +In `~/alice/sw/BUILD/O2Physics-latest-master/O2Physics` enter ninja and O2Physics environment (`alienv load ninja/latest O2Physics/latest`). Then build your task using `ninja stage/bin/`. If you don't know what you should type in `` place, open `CMakeList.txt` and see how your analysis is called there.
+Keep in mind that if you add a new file or modify CMakeList you need to use `cmake .` +Then, after building part, copy this builded file to directory with AOD file (`cp stage/bin/`). You can skip this step (copying) when you use `ninja install` instead of `ninja` or you can use alibuild. +____________________ +## How to run your code? + +In your directory with the AOD file, do the following:
+1. enter O2Physics envinronment, e.g with `alienv enter O2Physics/latest` +2. You need to connect to the GRID to acces remote configuration files (CCDB): type `alien.py` or `alien-token-init`. You will be asked for you password.
+3. Run your code as: +`./o2-analysistutorial-simple-analysis --aod-file [-b]`. Option `-b` stops the GUI from showing (batch mode).
+ +It is very likely that your task has dependencies: you have to run also the corresponding tasks (_helper tasks_). +For example, for our first task `cf-tutorial-task0` you would need to run: + +``` +o2-analysis-timestamp | \ +o2-analysis-track-propagation | \ +o2-analysis-cf-cf-tutorial-0 --aod-file AO2D.root +``` + +**Tip**: create a bash script with all the commands that you need! + +**Tip**: tasks have parameters that can be provided via command line. For example: +``` +o2-analysis-mytask --aod-file [-- ] +``` +When you have many parameters, it is better to provide them in a configuration file in json format: +``` +o2-analysis-mytask --configuration json:// +``` +In the following, we will use configuration files. + +### Possible errors +
Couldn't get TTree. +

+ +Sometimes you may get an error, for example: + ```c + [ERROR] Exception caught: Couldn't get TTree "DF_2853960297589372650/O2v0dataext from " + ``` +It means that `v0dataext` couldn't be found in your AOD file or it has not been produced by any attached helper task. +So now you know which table is missing. There are two paths you can choose;
+1. **EASIEST**: follow the instructions reported in [ALICE O2 documentation- Tree not found](https://aliceo2group.github.io/analysis-framework/docs/troubleshooting/treenotfound.html). After entering [ALICE O2 documentation - helper task tables](https://aliceo2group.github.io/analysis-framework/docs/datamodel/helperTaskTables.html), you search the table that you are missing and you will find the task you need to attach as dependency.
+2. More difficult: enter directory `alice/O2Physics` and look for the missing table.
+For example, if you are missing `pidtofka` table, you should type: +```c +grep -rnw . -e "PIDTOFKA" +grep -rnw . -e "PIDTOFKa" +grep -rnw . -e "pidTOFKa" +``` +You should see a list of files where this expression occurs: you need to find out the name of the file which produces this table. After you find it, you need to go to the corresponding `CMakeLists.txt` file. There, you will find the name of the task you are looking for. You can see that it has many sections but they all look alike. For example: +```c +o2physics_add_dpl_workflow( + SOURCES + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore + COMPONENT_NAME Analysis) +``` +So you need to find the **task-name** which will correspond to the **C++ file** you've found using grep ;)
+ + +

+
+
Fatal errors with non-existing CCDB entries. +

+While trying to run various O2 tasks/tutorials, you can run into fatal errors with non-existing CCDB entries for specific data.
+The reason is often the incorrect configuration of the paramenters. For example, for some executables such as `o2-analysis-timestamp` duging the option `--isRun2MC` could solve the problem. Or, simialary, using the oprion `--isMC` for o2-analysis-event-selection.
+For example: + +```c +o2-analysis-mm-dndeta --aod-file AODmc2.root --aod-memory-rate-limit 100000000000000 -b | \ +o2-analysis-pid-tpc -b | \ +o2-analysis-pid-tof -b | \ +o2-analysis-trackselection -b | \ +o2-analysis-trackextension -b | \ +o2-analysis-event-selection --isMC -b | \ +o2-analysis-timestamp --isRun2MC -b +``` + +

+
+ +____________________ +## How to obtain results of the analysis? +Running command `./o2-analysistutorial-simple-analysis --aod-file -b` (and others of that type) creates .root file and .json file.
+To enter AnalysisResults.root file enter O2Physics environment (`enter O2Physics/latest`) and type: `root -l` and then `new TBrowser`. (`-l` is optional but it runs root without additional information about it).
+You can change histograms manually or you can write macros and run them on .root file. If you've never written any root macros consider [_this repository_](https://github.com/zchochul/KADDre). You can find more on root and how to use it here -> [_root.cern/manual/_](https://root.cern/manual/first_steps_with_root/).
+_____________________________ +_____________________________ +# Tutorial checkpoints +## First task + We will be using [CFTutorialTask0.cxx](https://github.com/CF-tutorials/O2Physics/blob/tutorial/PWGCF/Tutorial/CFTutorialTask0.cxx). It's an example task illustrating how to create histograms and fill them with basic information. We will also apply basic event selection.
+ + Here you can see a structure of a typical analysis task in the O2:
+ ```c + struct myTask{ + Partition partition_name; + Filter filter_name; + Configurable name{}; + void init(){ + } + void process(){ + } + } + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc){ + WorkflowSpec workflow{}; + return workflow; + } + ``` +Each part will be described in greater detail further on during this tutorial.
+ +The first element of the task is `init` (equivalent to _UserCreateOutputObjects_ in _AliPhysics_). It looks like this: + + ```c + void init(o2::framework::InitContext&) + { + // Define your axes + // Constant bin width axis + AxisSpec vtxZAxis = {100, -20, 20}; + // Variable bin width axis + std::vector ptBinning = {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.}; + AxisSpec ptAxis = {ptBinning, "#it{p}_{T} (GeV/#it{c})"}; + + // Add histograms to histogram manager (as in the output object in AliPhysics) + histos.add("hZvtx_before_sel", ";Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hZvtx_after_sel", ";Z (cm)", kTH1F, {vtxZAxis}); + histos.add("hP", ";#it{p} (GeV/#it{c})", kTH1F, {{35, 0.5, 4.}}); + histos.add("hPt", ";#it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); + } + ``` +`init` is used to initialise objects, e.g. histograms, which will be used later in the process. + +The second element is `process`, equivalent to the _UserExec_ in _AliPhysics_. It looks like this: + +```c + void process(aod::Collision const& coll, aod::Tracks const& inputTracks) + { + // Performing the event selection + histos.fill(HIST("hZvtx_before_sel"), coll.posZ()); + if (fabs(coll.posZ()) > 10.f) { + return; + } + histos.fill(HIST("hZvtx_after_sel"), coll.posZ()); + + for (auto track : inputTracks) { // Loop over tracks + histos.fill(HIST("hP"), track.p()); + histos.fill(HIST("hPt"), track.pt()); + } + } + ``` + +The arguments of `process` are the data _tables_ that we analyse, i.e. the tables to which we _subscribe_. In the snippet above, the subscripion is to the tables of collisions and tracks. + +Finally, `WorkflowSpec` is necessay to add the task to the DPL workflow . And it looks like: + + ```c + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + // Equivalent to the AddTask in AliPhysics + WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} +``` + +## Second task + +We will be using [CFTutorialTask1.cxx](https://github.com/CF-tutorials/O2Physics/blob/tutorial/PWGCF/Tutorial/CFTutorialTask1.cxx). In this part of the tutorial, we will focus on how to access information from different tables. Sets of information stored in different tables can be put together using `Join`: + +```c +namespace o2::aod +{ +using MyCollision = soa::Join::iterator; +using MyTracks = soa::Join; +} // namespace o2::aod + ``` +The data model provides some predifined joins, suche as `FullTracks = soa::Join`. The complete list of predefined joins can be found in [ALICE O2 documentation - The Data Model, Joins and iterators](https://aliceo2group.github.io/analysis-framework/docs/datamodel/joinsAndIterators.html). + +Joined tables can be normally used as agruments of process. + +```c + // CFTutorialTask1.cxx version + void process(aod::MyCollision const& coll, aod::MyTracks const& inputTracks){...} + // CFTutorialTask0.cxx version + void process(aod::Collision const& coll, aod::Tracks const& inputTracks){...} +``` + +## Third task + +We will be using [CFTutorialTask2.cxx](https://github.com/CF-tutorials/O2Physics/blob/tutorial/PWGCF/Tutorial/CFTutorialTask2.cxx). In this part of the tutorial, we will focus on how to use **Configurables** and **Filters**.
+ +A `Configurable` is a parameter of the task, which can be set from command line or in the dedicated space in Hyperloop. +In the following, an example for the configurable used for the selection on the vertex z coordinate: +```c +Configurable ConfZvtxCut{"ConfZvtxCut", 10, "Z vtx cut"}; +``` +In the task, tha value of the configurable can be accesses simply by calling the Configurable itself. + +A `Filter` is used to select the rows of a table which satisfy particular requirements. For example: +```c +Filter trackFilter = (nabs(aod::track::eta) < ConfEtaCut) && (aod::track::pt > ConfMinPtCut) && (aod::track::pt < ConfMaxPtCut); +``` +Note that configurables can be used in the definition of a filters. + +## Fourth task + +We will be using [CFTutorialTask3.cxx](https://github.com/CF-tutorials/O2Physics/blob/tutorial/PWGCF/Tutorial/CFTutorialTask3.cxx). In this part of the tutorial, we will focus on how to create and use **partitions**.
+ +A `Partition` is a subset of a given table that satisfies particular requirements. In the following, a partition obtained from the table _Tracks_: + +```c +Partition positive = (nabs(aod::track::eta) < ConfEtaCut) && (aod::track::pt > ConfMinPtCut) && (aod::track::pt < ConfMaxPtCut) && (aod::track::signed1Pt > ConfChargeCut); +``` +Note that configurables can be used in the definition of a partitions. + +Partition can be used in the following way: + ```c +void process(MyFilteredCollision const& coll, o2::aod::Tracks const& tracks) +{ + + ... + + auto groupPositive = positive->sliceByCached(aod::track::collisionId, coll.globalIndex()); + + for (auto track : groupPositive) { + histos.fill(HIST("hChargePos"), track.sign()); + } + + ... +} +``` +**WARNING**: using a `Partition` of the table `Tracks`, you are considering **ALL** the tracks (which satisfy the requirements) of **ALL** the collisions. In order to select the elements corresponding to the relevant collision, one must use `sliceByCached`, as shown in the example above. + +

+ + +## Fifth task + +We will be using [CFTutorialTask4.cxx](https://github.com/CF-tutorials/O2Physics/blob/tutorial/PWGCF/Tutorial/CFTutorialTask4.cxx). In this part of the tutorial, we will focus on how to use and combine elements of different **partitions**. In the following, you can see the invariant mass of two pions, a negative one and a positive one, belonging to two different partitions. + +`combinations` returns a pair of elements taken from different partitions. `CombinationsFullIndexPolicy` is needed to combine all the element of the first set with all the element of the second set. + +```c +for (auto& [pos, neg] : combinations(soa::CombinationsFullIndexPolicy(groupPositive, groupNegative))) { + + if (fabs(pos.tpcNSigmaPi()) > 3 or fabs(neg.tpcNSigmaPi()) > 3) { + continue; + } + + TLorentzVector posVec; + posVec.SetPtEtaPhiM(pos.pt(), pos.eta(), pos.phi(), o2::constants::physics::MassPionCharged); + TLorentzVector negVec; + negVec.SetPtEtaPhiM(neg.pt(), neg.eta(), neg.phi(), o2::constants::physics::MassPionCharged); + + TLorentzVector sumVec(posVec); + sumVec += negVec; + histos.fill(HIST("hInvariantMass"), sumVec.M()); + } +``` + + +## Sixth task + +We will be using [CFTutorialTask5.cxx](https://github.com/CF-tutorials/O2Physics/blob/tutorial/PWGCF/Tutorial/CFTutorialTask5.cxx). In this part of the tutorial, we will show how to use multiple processes in the same task with **process switches** and how to access and combine elements of different **partitions** and **different events**. + +With diss task, we compute the invariant mass of two pions, one positive and one negative. +We have two separate process functions:
+ +1. `processSameEvent` computes the invariant mass for two pions produced in the same collision. + +2. `processMixed` computes the invariant mass for two pions produced in the different collisions. + +```c +void processSameEvent(){} +PROCESS_SWITCH(, processSameEvent, "Enable processing same event", true); + +void processMixed(){} +PROCESS_SWITCH(, processMixed, "Enable processing mixed event", true); +``` + +The process functions can be activated using `PROCESS_SWITCH`, setting the last parameter as `true`. This parameter can be configured via command line, json file or in the hyperloop interface. diff --git a/PWGCF/Tutorial/run-config.json b/PWGCF/Tutorial/run-config.json new file mode 100644 index 00000000000..e842cc5394e --- /dev/null +++ b/PWGCF/Tutorial/run-config.json @@ -0,0 +1,134 @@ +{ + "internal-dpl-clock": "", + "internal-dpl-aod-reader": { + "time-limit": "0", + "orbit-offset-enumeration": "0", + "orbit-multiplier-enumeration": "0", + "start-value-enumeration": "0", + "end-value-enumeration": "-1", + "step-value-enumeration": "1", + "aod-file": "pippo6.root" + }, + "internal-dpl-aod-index-builder": "", + "internal-dpl-aod-spawner": "", + "fdd-converter": "", + "timestamp-task": { + "verbose": "false", + "rct-path": "RCT/RunInformation/", + "start-orbit-path": "GRP/StartOrbit", + "ccdb-url": "http://alice-ccdb.cern.ch", + "isRun2MC": "false" + }, + "tpc-pid": { + "param-file": "", + "param-signal": "BetheBloch", + "param-sigma": "TPCReso", + "ccdb-url": "http://alice-ccdb.cern.ch", + "ccdbPath": "Analysis/PID/TPC/Response", + "ccdb-timestamp": "-1", + "pid-el": "-1", + "pid-mu": "-1", + "pid-pi": "-1", + "pid-ka": "-1", + "pid-pr": "-1", + "pid-de": "-1", + "pid-tr": "-1", + "pid-he": "-1", + "pid-al": "-1" + }, + "bc-selection-task": { + "processRun2": "false", + "processRun3": "true" + }, + "tof-signal": "", + "track-propagation": { + "ccdb-url": "http://alice-ccdb.cern.ch", + "lutPath": "GLO/Param/MatLUT", + "geoPath": "GLO/Config/GeometryAligned", + "grpPath": "GLO/GRP/GRP", + "mVtxPath": "GLO/Calib/MeanVertex", + "processStandard": "true", + "processCovariance": "false" + }, + "event-selection-task": { + "syst": "pp", + "muonSelection": "0", + "customDeltaBC": "300", + "isMC": "false", + "processRun2": "false", + "processRun3": "true" + }, + "multiplicity-table": { + "processRun2": "false", + "processRun3": "true" + }, + "track-selection": { + "isRun3": "true" + }, + "c-f-tutorial-task0": "", + "c-f-tutorial-task1": "", + "c-f-tutorial-task2": { + "ConfZvtxCut": "10", + "ConfEtaCut": "0.800000012", + "ConfMaxPtCut": "3", + "ConfMinPtCut": "0.5", + "ConfMinNSigmaTPCCut": "3" + }, + "c-f-tutorial-task3": { + "ConfZvtxCut": "10", + "ConfEtaCut": "0.800000012", + "ConfMaxPtCut": "3", + "ConfMinPtCut": "0.5", + "ConfMinNSigmaTPCCut": "3", + "ConfChargeCut": "0" + }, + "c-f-tutorial-task4": { + "ConfZvtxCut": "10", + "ConfEtaCut": "0.800000012", + "ConfMaxPtCut": "3", + "ConfMinPtCut": "0.5", + "ConfMinNSigmaTPCCut": "3", + "ConfChargeCut": "0" + }, + "c-f-tutorial-task5": { + "ConfZvtxCut": "10", + "ConfEtaCut": "0.800000012", + "ConfMaxPtCut": "3", + "ConfMinPtCut": "0.5", + "ConfMinNSigmaTPCCut": "3", + "ConfChargeCut": "0", + "ConfMultBins": { + "values": [ + "0", + "0", + "20", + "40", + "60", + "80", + "100", + "200", + "99999" + ] + }, + "ConfVtxBins": { + "values": [ + "0", + "-10", + "-8", + "-6", + "-4", + "-2", + "0", + "2", + "4", + "6", + "8", + "10" + ] + }, + "processSame": "true", + "processMixed": "true" + }, + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-aod-writer": "" +} diff --git a/PWGCF/Tutorial/run.sh b/PWGCF/Tutorial/run.sh new file mode 100755 index 00000000000..8d6b0fe422f --- /dev/null +++ b/PWGCF/Tutorial/run.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +config_file=$1 + +o2-analysis-timestamp --configuration json://"$config_file" --aod-memory-rate-limit 600000000 | + o2-analysis-event-selection --configuration json://"$config_file" --aod-memory-rate-limit 600000000 | + o2-analysis-multiplicity-table --configuration json://"$config_file" --aod-memory-rate-limit 600000000 | + o2-analysis-track-propagation --configuration json://"$config_file" --aod-memory-rate-limit 600000000 | + o2-analysis-pid-tpc --configuration json://"$config_file" --aod-memory-rate-limit 600000000 | + o2-analysis-cf-cf-tutorial-5 --configuration json://"$config_file" --aod-memory-rate-limit 600000000