diff --git a/Tutorials/PWGLF/Strangeness/CMakeLists.txt b/Tutorials/PWGLF/Strangeness/CMakeLists.txt index 6a9ca0389f0..3a2fe4d79ca 100644 --- a/Tutorials/PWGLF/Strangeness/CMakeLists.txt +++ b/Tutorials/PWGLF/Strangeness/CMakeLists.txt @@ -11,4 +11,4 @@ add_subdirectory(Original) add_subdirectory(Derived) - +add_subdirectory(StrangenessV0s_HandsOn/o2physics/AnalysisV0) diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/README.md b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/README.md new file mode 100644 index 00000000000..8b87bd5cae4 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/README.md @@ -0,0 +1,118 @@ +# Strangeness hands-on — V0s in pp @ √s = 5.36 TeV (derived data) + +In this hands-on session you will write an analysis task for **K0S, Λ and Λbar** on strangeness derived +data of pp collisions at 5.36 TeV, in 5 steps, starting from a skeleton. + +You will learn how to: +- use the strangeness derived data and structure your analysis task; +- reconstruct K0S, Λ and Λbar; +- apply topological, kinematic and PID (TPC and TOF) selections; +- access the MC information of the V0s to compute the efficiency. + +## Preparation + +Update O2Physics and enter the environment: + +```bash +alienv enter O2Physics/latest +which o2-analysistutorial-lf-strangeness-derived-v0-skeleton # must exist +which o2-analysistutorial-lf-strangeness-derived-v0-step0 # checkpoint +``` + +Clone this repository: + +```bash +git clone https://github.com/StrangenessV0s_HandsOn +cd StrangenessV0s_HandsOn +``` + +Download the two input files (strangeness derived data, ~<200> MB each): + +```bash +# real data -> data/AO2D.root (used by skeleton and steps 0-3) +rsync -r -u --progress USERNAME@lxplus.cern.ch:/eos/user///tutorialData/data/AO2D.root data +# Monte Carlo -> MC/AO2D.root (used by step 4, which needs the MC truth) +rsync -r -u --progress USERNAME@lxplus.cern.ch:/eos/user///tutorialData/MC/AO2D.root MC +``` + +Alternatively, download them from CERNBox links. + +The run scripts do not contain the file paths: they read them from two text files (one path per line, +relative to the repository folder or absolute): + +| File | Content | Used by | +|------------------|------------------|-----------------------------------| +| `input_data.txt` | `data/AO2D.root` | `runSkeleton.sh`, `runStep0-3.sh` | +| `input_MC.txt` | `MC/AO2D.root` | `runStep4.sh` | + +If you save the files elsewhere, edit these two text files. To run steps 0-3 on the MC (e.g. to compare +with data): `INPUTFILE=input_MC.txt ./runStep2.sh`. + +## How to work + +The code you will modify is the skeleton in O2Physics: +`Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_skeleton.cxx`. +The checkpoints of each step are in the same folder (`strangeness_derived_v0_stepX.cxx`). + +```bash +./runSkeleton.sh # "No problems!" must be printed +root -l results/skeleton/AnalysisResults.root +``` + +After modifying and recompiling the skeleton, run it with the configuration of a given step: + +```bash +TASK=o2-analysistutorial-lf-strangeness-derived-v0-skeleton ./runStep1.sh +``` + +Without `TASK=...` the checkpoint of the step is run: useful to compare with your results. + +| Step | What is added | Tables | What to look at | +|----------|-----------------------------------------------------------------------------------------|-------------------------------------------------|-------------------------------------------------| +| skeleton | loop over events, sel8, \|z\| < 10 cm | `StraCollisions`, `StraEvSels` | `eventSelection/hVertexZRec` | +| 0 | loop over V0s, K0S, Λ, Λbar invariant masses | `V0Cores` | `kzeroShort/hMassK0Short`, `lambda/hMassLambda` | +| 1 | topological selections (`Filter` + dynamic columns), rapidity, competing mass rejection | `V0Cores` | `hMass*Selected`, `hV0CosPA`, `hV0Radius` | +| 2 | TPC PID of the daughters (`posTrackExtra_as<>`) | `V0Extras`, `DauTrackExtras`, `DauTrackTPCPIDs` | `hNSigmaPos/NegPionFromK0s`, `hMass*Selected` | +| 3 | TOF PID optimised for secondary particles (`strangenesstofpid` task) | `V0TOFNSigmas` | `hMass*SelectedWithTOF` | +| 4 | MC truth: true reconstructed and generated V0s | `V0CoreMCLabels`, `V0MCCores`, `V0MCCollRefs` | `hPt*TrueRec`, `genParticles/hPt*Gen` | + +Step 1 selections (in `jsonConfigs/step1.json`): + +| Selection | Value | Getter | Column | +|------------------------------|-------------|--------------------------------|------------------------------| +| DCA pos./neg. daughter to PV | > 0.06 cm | `dcapostopv()`, `dcanegtopv()` | standard | +| DCA between daughters | < 0.5 cm | `dcaV0daughters()` | standard | +| cosine of pointing angle | > 0.995 | `v0cosPA()` | **standard** in derived data | +| decay radius | > 0.9 cm | `v0radius()` | dynamic | +| rapidity | \|y\| < 0.5 | `yK0Short()`, `yLambda()` | dynamic | + +Hints for the steps: +- **Step 0**: look at the `aod::V0Cores` table in `PWGLF/DataModel/LFStrangenessTables.h` and at the getters + `.mK0Short()`, `.mLambda()`, `.mAntiLambda()`. +- **Step 1**: keep only standard V0s (`v0Type() == 1`); a `Filter` cannot cut on dynamic columns. +- **Step 2**: K0S → π⁺π⁻, Λ → pπ⁻, Λbar → p̄π⁺. You need `LFStrangenessPIDTables.h`. +- **Step 3**: look at `.positiveHasTOF()`, `.negativeHasTOF()` and `.tofNSigmaK0PiPlus()`, `.tofNSigmaLaPr()`, … in `LFStrangenessPIDTables.h`. +- **Step 4**: `has_v0MCCore()`, `v0MCCore_as()`, `.pdgCode()` with `PDG_t::kK0Short`, + `PDG_t::kLambda0`, `PDG_t::kLambda0Bar`; select only primary particles (`.isPhysicalPrimary()`). + +## Checkpoints + +- **Step 0**: peaks at ~0.497 GeV/c² (K0S) and ~1.116 GeV/c² (Λ, Λbar), already visible thanks to the derived data pre-selections. +- **Step 1**: the background is reduced. +- **Step 2**: the Nσ bands of the pions from K0S are centred at 0; the background under the Λ and Λbar peaks is further reduced. +- **Step 3**: TOF further suppresses the combinatorial background. +- **Step 4**: `hPt*TrueRec / hPt*Gen` gives the efficiency (× acceptance) as a function of pT. + +## If something does not run + +```bash +root -l -b -q "checkTables.C(\"$(cat input_data.txt)\")" # data: step 4 "CANNOT run" is expected +root -l -b -q "checkTables.C(\"$(cat input_MC.txt)\")" # MC: all steps must be ok +``` + +The macro tells you which steps can run with the file and, if a table has an old version, which converter +to use: + +```bash +CONVERTERS='o2-analysis-lf-straevselsconverter6 ${OPTION} | ' ./runStep0.sh +``` diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/checkTables.C b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/checkTables.C new file mode 100644 index 00000000000..26372504761 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/checkTables.C @@ -0,0 +1,139 @@ +// 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 checkTables.C +/// \brief Checks which strangeness tables (and which versions) are present in a derived AO2D +/// and reports which steps of the V0 tutorial (o2-analysistutorial-lf-strangeness-derived-v0-*) can run. +/// +/// Usage: root -l -b -q 'checkTables.C("data/AO2D.root")' or something like root -l -b -q "checkTables.C(\"$(cat input_data.txt)\")" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct RequiredTable { + std::string base; // tree name without version, e.g. "o2straevsels" + int version{0}; // version required by the current O2Physics data model + int firstStep{-1}; // first step that uses it (-1 = skeleton) + std::string hint; // converter to use if the version in the file is older +}; + +int findVersion(TDirectory* dir, const std::string& base) +{ + int found = -1; + TIter next(dir->GetListOfKeys()); + while (TKey* key = dynamic_cast(next())) { + TString name = key->GetName(); + name.ToLower(); + if (name == base.c_str()) { + found = std::max(found, 0); + } else if (name.BeginsWith((base + "_").c_str())) { + TString v = name(base.size() + 1, name.Length()); + if (v.IsDigit()) { + found = std::max(found, v.Atoi()); + } + } + } + return found; +} + +void checkTables(const char* fname = "data/AO2D.root") +{ + const std::vector required = { + {.base = "o2stracollision", .version = 0, .firstStep = -1, .hint = ""}, + {.base = "o2straevsels", .version = 6, .firstStep = -1, .hint = "o2-analysis-lf-straevselsconverterN (chain up to straevselsconverter6)"}, + {.base = "o2v0core", .version = 0, .firstStep = 0, .hint = ""}, + {.base = "o2v0extra", .version = 0, .firstStep = 2, .hint = ""}, + {.base = "o2dautrackextra", .version = 3, .firstStep = 2, .hint = "o2-analysis-lf-stradautracksextraconverterN (up to stradautracksextraconverter3)"}, + {.base = "o2dautracktpcpid", .version = 1, .firstStep = 2, .hint = "o2-analysis-lf-stradautrackstpcpidconverter"}, + // step 3: tables read as input by the helper task strangenesstofpid, + // not by the analysis itself: the tutorial only uses V0s + {.base = "o2strastamps", .version = 1, .firstStep = 3, .hint = "o2-analysis-lf-strastampsconverter"}, + {.base = "o2straevtimes", .version = 1, .firstStep = 3, .hint = "o2-analysis-lf-stradautrackstofpidconverter3"}, + {.base = "o2dautracktofpid", .version = 3, .firstStep = 3, .hint = "o2-analysis-lf-stradautrackstofpidconverterN (up to stradautrackstofpidconverter4)"}, + {.base = "o2v0collref", .version = 0, .firstStep = 3, .hint = ""}, + {.base = "o2casccore", .version = 0, .firstStep = 3, .hint = ""}, + {.base = "o2cascextra", .version = 0, .firstStep = 3, .hint = ""}, + {.base = "o2casccollref", .version = 0, .firstStep = 3, .hint = ""}, + // step 4: MC + {.base = "o2v0coremclabel", .version = 0, .firstStep = 4, .hint = ""}, + {.base = "o2v0mccore", .version = 2, .firstStep = 4, .hint = "o2-analysis-lf-v0coresconverter / v0coresconverter2"}, + {.base = "o2v0mccollref", .version = 0, .firstStep = 4, .hint = ""}, + {.base = "o2stracolllabels", .version = 0, .firstStep = 4, .hint = ""}, + {.base = "o2stramccollision", .version = 2, .firstStep = 4, .hint = "o2-analysis-lf-stramccollisionconverter / stramccollisionconverter2"}, + }; + + TFile* f = TFile::Open(fname); + if (!f || f->IsZombie()) { + std::cout << "Cannot open " << fname << std::endl; + return; + } + TDirectory* df = nullptr; + TIter next(f->GetListOfKeys()); + while (TKey* key = dynamic_cast(next())) { + if (TString(key->GetName()).BeginsWith("DF_")) { + df = f->GetDirectory(key->GetName()); + break; + } + } + if (!df) { + std::cout << "No DF_* folder in " << fname << std::endl; + return; + } + + std::cout << "\nTrees in " << df->GetName() << ":\n"; + TIter nextTree(df->GetListOfKeys()); + while (TKey* key = dynamic_cast(nextTree())) { + std::cout << " " << key->GetName() << "\n"; + } + + int firstBrokenStep = 99; // first step that cannot run, even with converters + int firstConverterStep = 99; // first step that needs converters + std::cout << "\nTables required by the tutorial:\n"; + for (const auto& t : required) { + int v = findVersion(df, t.base); + TString status = "ok"; + if (v < 0) { + status = "MISSING"; + firstBrokenStep = std::min(firstBrokenStep, t.firstStep); + } else if (v < t.version) { + status = Form("v%d < v%d required", v, t.version); + firstConverterStep = std::min(firstConverterStep, t.firstStep); + } else if (v > t.version) { + status = Form("v%d > v%d: O2Physics is older than the data, update it", v, t.version); + firstBrokenStep = std::min(firstBrokenStep, t.firstStep); + } + TString step = t.firstStep < 0 ? "skeleton" : Form("step%d", t.firstStep); + std::cout << Form(" %-20s (from %-8s) %s", t.base.c_str(), step.Data(), status.Data()); + if (status != "ok" && !t.hint.empty() && v >= 0) { + std::cout << "\n -> " << t.hint; + } + std::cout << "\n"; + } + + std::cout << "\nSummary:\n"; + for (int s = -1; s <= 4; s++) { + TString name = s < 0 ? "skeleton" : Form("step%d", s); + TString res = s >= firstBrokenStep ? "CANNOT run with this file" + : s >= firstConverterStep ? "ok, but converters are needed" + : "ok"; + std::cout << Form(" %-8s %s\n", name.Data(), res.Data()); + } + std::cout << std::endl; + f->Close(); +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/input_MC.txt b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/input_MC.txt new file mode 100644 index 00000000000..900ccbc2fc1 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/input_MC.txt @@ -0,0 +1 @@ +file:///eos/user/s/spucillo/O2AT6_tutorial/MC/AO2D.root diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/input_data.txt b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/input_data.txt new file mode 100644 index 00000000000..9eff51ed538 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/input_data.txt @@ -0,0 +1 @@ +file:///eos/user/s/spucillo/O2AT6_tutorial/data/AO2D.root diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/skeleton.json b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/skeleton.json new file mode 100644 index 00000000000..d1b05b7f975 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/skeleton.json @@ -0,0 +1,20 @@ +{ + "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": "@input_data.txt" + }, + "internal-dpl-aod-spawner": "", + "strangeness-derived-v0-tutorial": { + "nBins": "100", + "cutzvertex": "10" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step0.json b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step0.json new file mode 100644 index 00000000000..d1b05b7f975 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step0.json @@ -0,0 +1,20 @@ +{ + "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": "@input_data.txt" + }, + "internal-dpl-aod-spawner": "", + "strangeness-derived-v0-tutorial": { + "nBins": "100", + "cutzvertex": "10" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step1.json b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step1.json new file mode 100644 index 00000000000..95faf947a1b --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step1.json @@ -0,0 +1,25 @@ +{ + "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": "@input_data.txt" + }, + "strangeness-derived-v0-tutorial": { + "nBins": "100", + "cutzvertex": "10", + "v0setting_dcav0dau": "0.5", + "v0setting_dcapostopv": "0.06", + "v0setting_dcanegtopv": "0.06", + "v0setting_cospa": "0.995", + "v0setting_radius": "0.9", + "v0setting_rapidity": "0.5" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step2.json b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step2.json new file mode 100644 index 00000000000..19301322340 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step2.json @@ -0,0 +1,27 @@ +{ + "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": "@input_data.txt" + }, + "strangeness-derived-v0-tutorial": { + "nBins": "100", + "cutzvertex": "10", + "v0setting_dcav0dau": "0.5", + "v0setting_dcapostopv": "0.06", + "v0setting_dcanegtopv": "0.06", + "v0setting_cospa": "0.995", + "v0setting_radius": "0.9", + "v0setting_rapidity": "0.5", + "NSigmaTPCPion": "4", + "NSigmaTPCProton": "4" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step3.json b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step3.json new file mode 100644 index 00000000000..171bb1cf638 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step3.json @@ -0,0 +1,198 @@ +{ + "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": "@input_data.txt" + }, + "strangenesstofpid": { + "v0Calibration.qaMassWindow": "0.005", + "axisP": { + "values": [ + 0, + 0, + 0.10000000149011612, + 0.20000000298023224, + 0.30000001192092896, + 0.4000000059604645, + 0.5, + 0.6000000238418579, + 0.699999988079071, + 0.800000011920929, + 0.8999999761581421, + 1, + 1.100000023841858, + 1.2000000476837158, + 1.2999999523162842, + 1.399999976158142, + 1.5, + 1.600000023841858, + 1.7000000476837158, + 1.7999999523162842, + 1.899999976158142, + 2, + 2.200000047683716, + 2.4000000953674316, + 2.5999999046325684, + 2.799999952316284, + 3, + 3.200000047683716, + 3.4000000953674316, + 3.5999999046325684, + 3.799999952316284, + 4, + 4.400000095367432, + 4.800000190734863, + 5.199999809265137, + 5.599999904632568, + 6, + 6.5, + 7, + 7.5, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 17, + 19, + 21, + 23, + 25, + 30, + 35, + 40, + 50 + ] + }, + "axisRatioMethods": { + "values": [ + 400, + 0.8999999761581421, + 1.899999976158142 + ] + }, + "v0Calibration.qaCosPA": "0.999", + "rejectUndefinedTof": "1", + "v0Calibration.qaDCADau": "0.5", + "axisDeltaTime": { + "values": [ + 2000, + -1000, + 1000 + ] + }, + "ccdb.ccdb-url": "http://alice-ccdb.cern.ch", + "v0Calibration.qaTPCNSigma": "5", + "ccdb.lutPath": "GLO/Param/MatLUT", + "axisDeltaTimeVsPrimaryCalculation": { + "values": [ + 500, + -500, + 500 + ] + }, + "axisEta": { + "values": [ + 20, + -1, + 1 + ] + }, + "axisTimeLong": { + "values": [ + 3000, + -1500000, + 1500000 + ] + }, + "calculationMethod": "0", + "calculateCascades": "0", + "axisNSigma": { + "values": [ + 200, + -10, + 10 + ] + }, + "axisSmallP": { + "values": [ + 250, + 0, + 2.5 + ] + }, + "manualRunNumber": "544122", + "calculateV0TOFPIDs": "-1", + "processDerivedData": "1", + "calculateV0s": "1", + "axisBCshift": { + "values": [ + 130, + -3006569.541579235, + 237032.45348549983 + ] + }, + "doBCshift": "1", + "useCustomRunNumber": "0", + "axisPosition": { + "values": [ + 400, + -400, + 400 + ] + }, + "processStandardData": "0", + "axisTime": { + "values": [ + 400, + 10000, + 50000 + ] + }, + "calculateCascTOFPIDs": "0", + "ccdb.mVtxPath": "GLO/Calib/MeanVertex", + "calculateV0TOFDebugs": "-1", + "axisSnp": { + "values": [ + 220, + -1.100000023841858, + 1.100000023841858 + ] + }, + "ccdb.grpmagPath": "GLO/Config/GRPMagField", + "ccdb.grpPath": "GLO/GRP/GRP", + "doNSigmas": "1", + "calculateV0TOFBetas": "-1", + "reassociateTracks": "1", + "ccdb.nSigmaPath": "Users/d/ddobrigk/stratof", + "doQA": "0", + "d_bz": "-999", + "tofPosition": "377.934", + "doQANSigma": "0" + }, + "strangeness-derived-v0-tutorial": { + "nBins": "100", + "cutzvertex": "10", + "v0setting_dcav0dau": "0.5", + "v0setting_dcapostopv": "0.06", + "v0setting_dcanegtopv": "0.06", + "v0setting_cospa": "0.995", + "v0setting_radius": "0.9", + "v0setting_rapidity": "0.5", + "NSigmaTPCPion": "4", + "NSigmaTPCProton": "4", + "NSigmaTOFPion": "3", + "NSigmaTOFProton": "3" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step4.json b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step4.json new file mode 100644 index 00000000000..94a48da0c81 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/jsonConfigs/step4.json @@ -0,0 +1,200 @@ +{ + "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": "@input_MC.txt" + }, + "strangenesstofpid": { + "v0Calibration.qaMassWindow": "0.005", + "axisP": { + "values": [ + 0, + 0, + 0.10000000149011612, + 0.20000000298023224, + 0.30000001192092896, + 0.4000000059604645, + 0.5, + 0.6000000238418579, + 0.699999988079071, + 0.800000011920929, + 0.8999999761581421, + 1, + 1.100000023841858, + 1.2000000476837158, + 1.2999999523162842, + 1.399999976158142, + 1.5, + 1.600000023841858, + 1.7000000476837158, + 1.7999999523162842, + 1.899999976158142, + 2, + 2.200000047683716, + 2.4000000953674316, + 2.5999999046325684, + 2.799999952316284, + 3, + 3.200000047683716, + 3.4000000953674316, + 3.5999999046325684, + 3.799999952316284, + 4, + 4.400000095367432, + 4.800000190734863, + 5.199999809265137, + 5.599999904632568, + 6, + 6.5, + 7, + 7.5, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 17, + 19, + 21, + 23, + 25, + 30, + 35, + 40, + 50 + ] + }, + "axisRatioMethods": { + "values": [ + 400, + 0.8999999761581421, + 1.899999976158142 + ] + }, + "v0Calibration.qaCosPA": "0.999", + "rejectUndefinedTof": "1", + "v0Calibration.qaDCADau": "0.5", + "axisDeltaTime": { + "values": [ + 2000, + -1000, + 1000 + ] + }, + "ccdb.ccdb-url": "http://alice-ccdb.cern.ch", + "v0Calibration.qaTPCNSigma": "5", + "ccdb.lutPath": "GLO/Param/MatLUT", + "axisDeltaTimeVsPrimaryCalculation": { + "values": [ + 500, + -500, + 500 + ] + }, + "axisEta": { + "values": [ + 20, + -1, + 1 + ] + }, + "axisTimeLong": { + "values": [ + 3000, + -1500000, + 1500000 + ] + }, + "calculationMethod": "0", + "calculateCascades": "0", + "axisNSigma": { + "values": [ + 200, + -10, + 10 + ] + }, + "axisSmallP": { + "values": [ + 250, + 0, + 2.5 + ] + }, + "manualRunNumber": "544122", + "calculateV0TOFPIDs": "-1", + "processDerivedData": "1", + "calculateV0s": "1", + "axisBCshift": { + "values": [ + 130, + -3006569.541579235, + 237032.45348549983 + ] + }, + "doBCshift": "1", + "useCustomRunNumber": "0", + "axisPosition": { + "values": [ + 400, + -400, + 400 + ] + }, + "processStandardData": "0", + "axisTime": { + "values": [ + 400, + 10000, + 50000 + ] + }, + "calculateCascTOFPIDs": "0", + "ccdb.mVtxPath": "GLO/Calib/MeanVertex", + "calculateV0TOFDebugs": "-1", + "axisSnp": { + "values": [ + 220, + -1.100000023841858, + 1.100000023841858 + ] + }, + "ccdb.grpmagPath": "GLO/Config/GRPMagField", + "ccdb.grpPath": "GLO/GRP/GRP", + "doNSigmas": "1", + "calculateV0TOFBetas": "-1", + "reassociateTracks": "1", + "ccdb.nSigmaPath": "Users/d/ddobrigk/stratof", + "doQA": "0", + "d_bz": "-999", + "tofPosition": "377.934", + "doQANSigma": "0" + }, + "strangeness-derived-v0-tutorial": { + "nBins": "100", + "cutzvertex": "10", + "v0setting_dcav0dau": "0.5", + "v0setting_dcapostopv": "0.06", + "v0setting_dcanegtopv": "0.06", + "v0setting_cospa": "0.995", + "v0setting_radius": "0.9", + "v0setting_rapidity": "0.5", + "NSigmaTPCPion": "4", + "NSigmaTPCProton": "4", + "NSigmaTOFPion": "3", + "NSigmaTOFProton": "3", + "processRecMC": "1", + "processGenMC": "1" + }, + "internal-dpl-aod-writer": "", + "internal-dpl-aod-global-analysis-file-sink": "", + "internal-dpl-injected-dummy-sink": "" +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/CMakeLists.txt b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/CMakeLists.txt new file mode 100644 index 00000000000..5e598293329 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/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(strangeness-derived-v0-skeleton + SOURCES strangeness_derived_v0_skeleton.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-derived-v0-step0 + SOURCES strangeness_derived_v0_step0.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-derived-v0-step1 + SOURCES strangeness_derived_v0_step1.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-derived-v0-step2 + SOURCES strangeness_derived_v0_step2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-derived-v0-step3 + SOURCES strangeness_derived_v0_step3.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) + +o2physics_add_dpl_workflow(strangeness-derived-v0-step4 + SOURCES strangeness_derived_v0_step4.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME AnalysisTutorial) diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_skeleton.cxx b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_skeleton.cxx new file mode 100644 index 00000000000..bcb1d62db4d --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_skeleton.cxx @@ -0,0 +1,81 @@ +// 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. +/// +/// \brief Skeleton of the V0 strangeness tutorial on derived data (K0S, Lambda, AntiLambda) +/// \author Sara Pucillo +/// based on the O2AT strangeness derived-data tutorial from: +/// \author Romain Schotter +/// and on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// SKELETON +// Starting point of the V0 tutorial: loop over the selected events (sel8, |z| < 10 cm) +// and fill a histogram with the z position of the primary vertex. +// Goal of the hands-on: improve this file step by step up to step 4 +// (checkpoints: strangeness_derived_v0_stepX.cxx). + +struct StrangenessDerivedV0Skeleton { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for histograms + Configurable nBins{"nBins", 100, "N bins in all histos"}; + + // Configurable for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + + void init(InitContext const&) + { + // Axes + AxisSpec vertexZAxis = {nBins, -15., 15., "vrtx_{Z} [cm]"}; + + // Histograms + // Event selection + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + } + + // Defining filters for events (event selection) + // Processed events will be already fulfilling the event selection requirements + Filter eventFilter = (o2::aod::evsel::sel8 == true); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); + + void process(soa::Filtered>::iterator const& collision) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"strangeness-derived-v0-tutorial"})}; +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step0.cxx b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step0.cxx new file mode 100644 index 00000000000..91839e54a54 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step0.cxx @@ -0,0 +1,96 @@ +// 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. +/// +/// \brief Step0 of the V0 strangeness tutorial on derived data (K0S, Lambda, AntiLambda) +/// \author Sara Pucillo +/// based on the O2AT strangeness derived-data tutorial from: +/// \author Romain Schotter +/// and on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Starting point: loop over all V0s and fill invariant mass histograms + +struct StrangenessDerivedV0Step0 { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rK0Short{"kzeroShort", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambda{"lambda", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for histograms + Configurable nBins{"nBins", 100, "N bins in all histos"}; + + // Configurable for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + + void init(InitContext const&) + { + // Axes + AxisSpec K0ShortMassAxis = {100, 0.45f, 0.55f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec LambdaMassAxis = {100, 1.08f, 1.15f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec vertexZAxis = {nBins, -15., 15., "vrtx_{Z} [cm]"}; + + // Histograms + // Event selection + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + + // K0S/Lambda/AntiLambda reconstruction + rK0Short.add("hMassK0Short", "hMassK0Short", {HistType::kTH1F, {K0ShortMassAxis}}); + + rLambda.add("hMassLambda", "hMassLambda", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambda", "hMassAntiLambda", {HistType::kTH1F, {LambdaMassAxis}}); + } + + // Defining filters for events (event selection) + // Processed events will be already fulfilling the event selection requirements + Filter eventFilter = (o2::aod::evsel::sel8 == true); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); + + void process(soa::Filtered>::iterator const& collision, + aod::V0Cores const& V0s) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + + // V0s + for (const auto& v0 : V0s) { + rK0Short.fill(HIST("hMassK0Short"), v0.mK0Short()); + rLambda.fill(HIST("hMassLambda"), v0.mLambda()); + rLambda.fill(HIST("hMassAntiLambda"), v0.mAntiLambda()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"strangeness-derived-v0-tutorial"})}; +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step1.cxx b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step1.cxx new file mode 100644 index 00000000000..09d7e29eb72 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step1.cxx @@ -0,0 +1,158 @@ +// 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. +/// +/// \brief Step1 of the V0 strangeness tutorial on derived data (K0S, Lambda, AntiLambda) +/// \author Sara Pucillo +/// based on the O2AT strangeness derived-data tutorial from: +/// \author Romain Schotter +/// and on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Starting point: loop over all V0s and fill invariant mass histograms +// STEP 1 +// Apply selections on topological variables of V0s + +struct StrangenessDerivedV0Step1 { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rK0Short{"kzeroShort", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambda{"lambda", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for histograms + Configurable nBins{"nBins", 100, "N bins in all histos"}; + + // Configurable for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + + // Configurable parameters for V0 selection + Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 0.5, "DCA V0 daughters"}; + Configurable v0setting_dcapostopv{"v0setting_dcapostopv", 0.06, "DCA positive to PV"}; + Configurable v0setting_dcanegtopv{"v0setting_dcanegtopv", 0.06, "DCA negative to PV"}; + Configurable v0setting_cospa{"v0setting_cospa", 0.995, "V0 CosPA"}; + Configurable v0setting_radius{"v0setting_radius", 0.9, "V0 radius"}; + Configurable v0setting_rapidity{"v0setting_rapidity", 0.5, "V0 rapidity window"}; + + void init(InitContext const&) + { + // Axes + AxisSpec K0ShortMassAxis = {100, 0.45f, 0.55f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec LambdaMassAxis = {100, 1.08f, 1.15f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec vertexZAxis = {nBins, -15., 15., "vrtx_{Z} [cm]"}; + + // Histograms + // Event selection + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + + // K0S/Lambda/AntiLambda reconstruction + rK0Short.add("hMassK0Short", "hMassK0Short", {HistType::kTH1F, {K0ShortMassAxis}}); + rK0Short.add("hMassK0ShortSelected", "hMassK0ShortSelected", {HistType::kTH1F, {K0ShortMassAxis}}); + + rLambda.add("hMassLambda", "hMassLambda", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambda", "hMassAntiLambda", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassLambdaSelected", "hMassLambdaSelected", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambdaSelected", "hMassAntiLambdaSelected", {HistType::kTH1F, {LambdaMassAxis}}); + + // V0 topological variables (after selections) + rK0Short.add("hV0DCADaughters", "hV0DCADaughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rK0Short.add("hV0CosPA", "hV0CosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + rK0Short.add("hV0Radius", "hV0Radius", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + } + + // Defining filters for events (event selection) + // Processed events will be already fulfilling the event selection requirements + Filter eventFilter = (o2::aod::evsel::sel8 == true); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); + + // Filters on V0s + // Cannot filter on dynamic columns + Filter preFilterV0 = (aod::v0data::dcaV0daughters < v0setting_dcav0dau && + nabs(aod::v0data::dcapostopv) > v0setting_dcapostopv && + nabs(aod::v0data::dcanegtopv) > v0setting_dcanegtopv); + + void process(soa::Filtered>::iterator const& collision, + soa::Filtered const& V0s) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + + // V0s + for (const auto& v0 : V0s) { + rK0Short.fill(HIST("hMassK0Short"), v0.mK0Short()); + rLambda.fill(HIST("hMassLambda"), v0.mLambda()); + rLambda.fill(HIST("hMassAntiLambda"), v0.mAntiLambda()); + + // Keep only standard V0s (type 1): type 0 = not passing the standard V0 selections, 2-3 = photon-like (TPC-only) + if (v0.v0Type() != 1) { + continue; + } + // Topological selections not applied in the Filter + // (in V0Cores the cosine of pointing angle is a regular column: it could also be moved into the Filter) + if (v0.v0cosPA() < v0setting_cospa) { + continue; + } + // Cut on dynamic columns + if (v0.v0radius() < v0setting_radius) { + continue; + } + // From here on, the same V0 is tested under the three mass hypotheses (K0S, Lambda, AntiLambda): + // the hypothesis-dependent selections cannot use 'continue', they are stored in booleans + + // Kinematic selection + bool isK0Short = std::abs(v0.yK0Short()) < v0setting_rapidity; + bool isLambda = std::abs(v0.yLambda()) < v0setting_rapidity; + bool isAntiLambda = std::abs(v0.yLambda()) < v0setting_rapidity; + + // Fill histograms! (if possible) + if (isK0Short) { + rK0Short.fill(HIST("hMassK0ShortSelected"), v0.mK0Short()); + + rK0Short.fill(HIST("hV0DCADaughters"), v0.dcaV0daughters()); + rK0Short.fill(HIST("hV0CosPA"), v0.v0cosPA()); + rK0Short.fill(HIST("hV0Radius"), v0.v0radius()); + } + if (isLambda) { + rLambda.fill(HIST("hMassLambdaSelected"), v0.mLambda()); + } + if (isAntiLambda) { + rLambda.fill(HIST("hMassAntiLambdaSelected"), v0.mAntiLambda()); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"strangeness-derived-v0-tutorial"})}; +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step2.cxx b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step2.cxx new file mode 100644 index 00000000000..18f2e22ecf8 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step2.cxx @@ -0,0 +1,200 @@ +// 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. +/// +/// \brief Step2 of the V0 strangeness tutorial on derived data (K0S, Lambda, AntiLambda) +/// \author Sara Pucillo +/// based on the O2AT strangeness derived-data tutorial from: +/// \author Romain Schotter +/// and on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Starting point: loop over all V0s and fill invariant mass histograms +// STEP 1 +// Apply selections on topological variables of V0s +// STEP 2 +// Apply TPC PID selections on V0 daughter tracks + +struct StrangenessDerivedV0Step2 { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rK0Short{"kzeroShort", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambda{"lambda", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for histograms + Configurable nBins{"nBins", 100, "N bins in all histos"}; + + // Configurable for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + + // Configurable parameters for V0 selection + Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 0.5, "DCA V0 daughters"}; + Configurable v0setting_dcapostopv{"v0setting_dcapostopv", 0.06, "DCA positive to PV"}; + Configurable v0setting_dcanegtopv{"v0setting_dcanegtopv", 0.06, "DCA negative to PV"}; + Configurable v0setting_cospa{"v0setting_cospa", 0.995, "V0 CosPA"}; + Configurable v0setting_radius{"v0setting_radius", 0.9, "V0 radius"}; + Configurable v0setting_rapidity{"v0setting_rapidity", 0.5, "V0 rapidity window"}; + + // Configurable parameters for PID selection + Configurable NSigmaTPCPion{"NSigmaTPCPion", 4, "NSigmaTPCPion"}; + Configurable NSigmaTPCProton{"NSigmaTPCProton", 4, "NSigmaTPCProton"}; + + void init(InitContext const&) + { + // Axes + AxisSpec K0ShortMassAxis = {100, 0.45f, 0.55f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec LambdaMassAxis = {100, 1.08f, 1.15f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec vertexZAxis = {nBins, -15., 15., "vrtx_{Z} [cm]"}; + AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec nSigmaAxis = {100, -10.0f, 10.0f, "N#sigma_{TPC}"}; + + // Histograms + // Event selection + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + + // K0S/Lambda/AntiLambda reconstruction + rK0Short.add("hMassK0Short", "hMassK0Short", {HistType::kTH1F, {K0ShortMassAxis}}); + rK0Short.add("hMassK0ShortSelected", "hMassK0ShortSelected", {HistType::kTH1F, {K0ShortMassAxis}}); + + rLambda.add("hMassLambda", "hMassLambda", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambda", "hMassAntiLambda", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassLambdaSelected", "hMassLambdaSelected", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambdaSelected", "hMassAntiLambdaSelected", {HistType::kTH1F, {LambdaMassAxis}}); + + // V0 topological variables (after selections) + rK0Short.add("hV0DCADaughters", "hV0DCADaughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rK0Short.add("hV0CosPA", "hV0CosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + rK0Short.add("hV0Radius", "hV0Radius", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + + // TPC PID of the K0S daughters, in the K0S peak region, before the PID selection + rK0Short.add("hNSigmaPosPionFromK0s", "hNSigmaPosPionFromK0s", {HistType::kTH2F, {ptAxis, nSigmaAxis}}); + rK0Short.add("hNSigmaNegPionFromK0s", "hNSigmaNegPionFromK0s", {HistType::kTH2F, {ptAxis, nSigmaAxis}}); + } + + // Defining filters for events (event selection) + // Processed events will be already fulfilling the event selection requirements + Filter eventFilter = (o2::aod::evsel::sel8 == true); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); + + // Filters on V0s + // Cannot filter on dynamic columns + Filter preFilterV0 = (aod::v0data::dcaV0daughters < v0setting_dcav0dau && + nabs(aod::v0data::dcapostopv) > v0setting_dcapostopv && + nabs(aod::v0data::dcanegtopv) > v0setting_dcanegtopv); + + // Defining the type of the daughter tracks + using dauTracks = soa::Join; + + void process(soa::Filtered>::iterator const& collision, + soa::Filtered> const& V0s, + dauTracks const&) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + + // V0s + for (const auto& v0 : V0s) { + const auto& posDaughterTrack = v0.posTrackExtra_as(); + const auto& negDaughterTrack = v0.negTrackExtra_as(); + + rK0Short.fill(HIST("hMassK0Short"), v0.mK0Short()); + rLambda.fill(HIST("hMassLambda"), v0.mLambda()); + rLambda.fill(HIST("hMassAntiLambda"), v0.mAntiLambda()); + + // Keep only standard V0s (type 1): type 0 = not passing the standard V0 selections, 2-3 = photon-like (TPC-only) + if (v0.v0Type() != 1) { + continue; + } + // Topological selections not applied in the Filter + // (in V0Cores the cosine of pointing angle is a regular column: it could also be moved into the Filter) + if (v0.v0cosPA() < v0setting_cospa) { + continue; + } + // Cut on dynamic columns + if (v0.v0radius() < v0setting_radius) { + continue; + } + + // From here on, the same V0 is tested under the three mass hypotheses (K0S, Lambda, AntiLambda): + // the hypothesis-dependent selections cannot use 'continue', they are stored in booleans + + // Kinematic selection + bool isK0Short = std::abs(v0.yK0Short()) < v0setting_rapidity; + bool isLambda = std::abs(v0.yLambda()) < v0setting_rapidity; + bool isAntiLambda = std::abs(v0.yLambda()) < v0setting_rapidity; + + // TPC PID QA of the K0S daughters (in the K0S peak region, before the PID selection) + if (isK0Short && std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < 0.01) { + rK0Short.fill(HIST("hNSigmaPosPionFromK0s"), v0.positivept(), posDaughterTrack.tpcNSigmaPi()); + rK0Short.fill(HIST("hNSigmaNegPionFromK0s"), v0.negativept(), negDaughterTrack.tpcNSigmaPi()); + } + + // TPC PID selection + // K0S -> pi+ pi- + if (std::abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion || std::abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + isK0Short = false; + } + // Lambda -> p pi- + if (std::abs(posDaughterTrack.tpcNSigmaPr()) > NSigmaTPCProton || std::abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + isLambda = false; + } + // AntiLambda -> pbar pi+ + if (std::abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion || std::abs(negDaughterTrack.tpcNSigmaPr()) > NSigmaTPCProton) { + isAntiLambda = false; + } + + // Fill histograms! (if possible) + if (isK0Short) { + rK0Short.fill(HIST("hMassK0ShortSelected"), v0.mK0Short()); + + rK0Short.fill(HIST("hV0DCADaughters"), v0.dcaV0daughters()); + rK0Short.fill(HIST("hV0CosPA"), v0.v0cosPA()); + rK0Short.fill(HIST("hV0Radius"), v0.v0radius()); + } + if (isLambda) { + rLambda.fill(HIST("hMassLambdaSelected"), v0.mLambda()); + } + if (isAntiLambda) { + rLambda.fill(HIST("hMassAntiLambdaSelected"), v0.mAntiLambda()); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"strangeness-derived-v0-tutorial"})}; +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step3.cxx b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step3.cxx new file mode 100644 index 00000000000..5ac5ed34f86 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step3.cxx @@ -0,0 +1,246 @@ +// 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. +/// +/// \brief Step3 of the V0 strangeness tutorial on derived data (K0S, Lambda, AntiLambda) +/// \author Sara Pucillo +/// based on the O2AT strangeness derived-data tutorial from: +/// \author Romain Schotter +/// and on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Starting point: loop over all V0s and fill invariant mass histograms +// STEP 1 +// Apply selections on topological variables of V0s +// STEP 2 +// Apply TPC PID selections on V0 daughter tracks +// STEP 3 +// Apply TOF PID selections on V0 daughter tracks (if info is available) + +struct StrangenessDerivedV0Step3 { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rK0Short{"kzeroShort", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambda{"lambda", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for histograms + Configurable nBins{"nBins", 100, "N bins in all histos"}; + + // Configurable for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + + // Configurable parameters for V0 selection + Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 0.5, "DCA V0 daughters"}; + Configurable v0setting_dcapostopv{"v0setting_dcapostopv", 0.06, "DCA positive to PV"}; + Configurable v0setting_dcanegtopv{"v0setting_dcanegtopv", 0.06, "DCA negative to PV"}; + Configurable v0setting_cospa{"v0setting_cospa", 0.995, "V0 CosPA"}; + Configurable v0setting_radius{"v0setting_radius", 0.9, "V0 radius"}; + Configurable v0setting_rapidity{"v0setting_rapidity", 0.5, "V0 rapidity window"}; + + // Configurable parameters for PID selection + Configurable NSigmaTPCPion{"NSigmaTPCPion", 4, "NSigmaTPCPion"}; + Configurable NSigmaTPCProton{"NSigmaTPCProton", 4, "NSigmaTPCProton"}; + + // Configurable parameters for TOF PID selection + Configurable NSigmaTOFPion{"NSigmaTOFPion", 3, "NSigmaTOFPion"}; + Configurable NSigmaTOFProton{"NSigmaTOFProton", 3, "NSigmaTOFProton"}; + + void init(InitContext const&) + { + // Axes + AxisSpec K0ShortMassAxis = {100, 0.45f, 0.55f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec LambdaMassAxis = {100, 1.08f, 1.15f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec vertexZAxis = {nBins, -15., 15., "vrtx_{Z} [cm]"}; + AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec nSigmaAxis = {100, -10.0f, 10.0f, "N#sigma_{TPC}"}; + + // Histograms + // Event selection + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + + // K0S/Lambda/AntiLambda reconstruction + rK0Short.add("hMassK0Short", "hMassK0Short", {HistType::kTH1F, {K0ShortMassAxis}}); + rK0Short.add("hMassK0ShortSelected", "hMassK0ShortSelected", {HistType::kTH1F, {K0ShortMassAxis}}); + rK0Short.add("hMassK0ShortSelectedWithTOF", "hMassK0ShortSelectedWithTOF", {HistType::kTH1F, {K0ShortMassAxis}}); + + rLambda.add("hMassLambda", "hMassLambda", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambda", "hMassAntiLambda", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassLambdaSelected", "hMassLambdaSelected", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambdaSelected", "hMassAntiLambdaSelected", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassLambdaSelectedWithTOF", "hMassLambdaSelectedWithTOF", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambdaSelectedWithTOF", "hMassAntiLambdaSelectedWithTOF", {HistType::kTH1F, {LambdaMassAxis}}); + + // V0 topological variables (after selections) + rK0Short.add("hV0DCADaughters", "hV0DCADaughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rK0Short.add("hV0CosPA", "hV0CosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + rK0Short.add("hV0Radius", "hV0Radius", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + + // TPC PID of the K0S daughters, in the K0S peak region, before the PID selection + rK0Short.add("hNSigmaPosPionFromK0s", "hNSigmaPosPionFromK0s", {HistType::kTH2F, {ptAxis, nSigmaAxis}}); + rK0Short.add("hNSigmaNegPionFromK0s", "hNSigmaNegPionFromK0s", {HistType::kTH2F, {ptAxis, nSigmaAxis}}); + } + + // Defining filters for events (event selection) + // Processed events will be already fulfilling the event selection requirements + Filter eventFilter = (o2::aod::evsel::sel8 == true); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); + + // Filters on V0s + // Cannot filter on dynamic columns + Filter preFilterV0 = (aod::v0data::dcaV0daughters < v0setting_dcav0dau && + nabs(aod::v0data::dcapostopv) > v0setting_dcapostopv && + nabs(aod::v0data::dcanegtopv) > v0setting_dcanegtopv); + + // Defining the type of the daughter tracks + using dauTracks = soa::Join; + + void process(soa::Filtered>::iterator const& collision, + soa::Filtered> const& V0s, + dauTracks const&) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + + // V0s + for (const auto& v0 : V0s) { + const auto& posDaughterTrack = v0.posTrackExtra_as(); + const auto& negDaughterTrack = v0.negTrackExtra_as(); + + rK0Short.fill(HIST("hMassK0Short"), v0.mK0Short()); + rLambda.fill(HIST("hMassLambda"), v0.mLambda()); + rLambda.fill(HIST("hMassAntiLambda"), v0.mAntiLambda()); + + // Keep only standard V0s (type 1): type 0 = not passing the standard V0 selections, 2-3 = photon-like (TPC-only) + if (v0.v0Type() != 1) { + continue; + } + // Topological selections not applied in the Filter + // (in V0Cores the cosine of pointing angle is a regular column: it could also be moved into the Filter) + if (v0.v0cosPA() < v0setting_cospa) { + continue; + } + // Cut on dynamic columns + if (v0.v0radius() < v0setting_radius) { + continue; + } + + // From here on, the same V0 is tested under the three mass hypotheses (K0S, Lambda, AntiLambda): + // the hypothesis-dependent selections cannot use 'continue', they are stored in booleans + + // Kinematic selection + bool isK0Short = std::abs(v0.yK0Short()) < v0setting_rapidity; + bool isLambda = std::abs(v0.yLambda()) < v0setting_rapidity; + bool isAntiLambda = std::abs(v0.yLambda()) < v0setting_rapidity; + + // TPC PID QA of the K0S daughters (in the K0S peak region, before the PID selection) + if (isK0Short && std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < 0.01) { + rK0Short.fill(HIST("hNSigmaPosPionFromK0s"), v0.positivept(), posDaughterTrack.tpcNSigmaPi()); + rK0Short.fill(HIST("hNSigmaNegPionFromK0s"), v0.negativept(), negDaughterTrack.tpcNSigmaPi()); + } + + // TPC PID selection + // K0S -> pi+ pi- + if (std::abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion || std::abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + isK0Short = false; + } + // Lambda -> p pi- + if (std::abs(posDaughterTrack.tpcNSigmaPr()) > NSigmaTPCProton || std::abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + isLambda = false; + } + // AntiLambda -> pbar pi+ + if (std::abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion || std::abs(negDaughterTrack.tpcNSigmaPr()) > NSigmaTPCProton) { + isAntiLambda = false; + } + + // TOF PID check (applied only if the daughter has a TOF signal) + bool k0ShortPassTOFSelection = true; + bool lambdaPassTOFSelection = true; + bool antiLambdaPassTOFSelection = true; + if (v0.positiveHasTOF()) { + if (std::abs(v0.tofNSigmaK0PiPlus()) > NSigmaTOFPion) { + k0ShortPassTOFSelection &= false; + } + if (std::abs(v0.tofNSigmaLaPr()) > NSigmaTOFProton) { + lambdaPassTOFSelection &= false; + } + if (std::abs(v0.tofNSigmaALaPi()) > NSigmaTOFPion) { + antiLambdaPassTOFSelection &= false; + } + } + if (v0.negativeHasTOF()) { + if (std::abs(v0.tofNSigmaK0PiMinus()) > NSigmaTOFPion) { + k0ShortPassTOFSelection &= false; + } + if (std::abs(v0.tofNSigmaLaPi()) > NSigmaTOFPion) { + lambdaPassTOFSelection &= false; + } + if (std::abs(v0.tofNSigmaALaPr()) > NSigmaTOFProton) { + antiLambdaPassTOFSelection &= false; + } + } + // Equivalent short form: v0.tofK0ShortCompatibility(nSigma), v0.tofLambdaCompatibility(nSigma), ... + + // Fill histograms! (if possible) + if (isK0Short) { + rK0Short.fill(HIST("hMassK0ShortSelected"), v0.mK0Short()); + if (k0ShortPassTOFSelection) { + rK0Short.fill(HIST("hMassK0ShortSelectedWithTOF"), v0.mK0Short()); + } + + rK0Short.fill(HIST("hV0DCADaughters"), v0.dcaV0daughters()); + rK0Short.fill(HIST("hV0CosPA"), v0.v0cosPA()); + rK0Short.fill(HIST("hV0Radius"), v0.v0radius()); + } + if (isLambda) { + rLambda.fill(HIST("hMassLambdaSelected"), v0.mLambda()); + if (lambdaPassTOFSelection) { + rLambda.fill(HIST("hMassLambdaSelectedWithTOF"), v0.mLambda()); + } + } + if (isAntiLambda) { + rLambda.fill(HIST("hMassAntiLambdaSelected"), v0.mAntiLambda()); + if (antiLambdaPassTOFSelection) { + rLambda.fill(HIST("hMassAntiLambdaSelectedWithTOF"), v0.mAntiLambda()); + } + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"strangeness-derived-v0-tutorial"})}; +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step4.cxx b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step4.cxx new file mode 100644 index 00000000000..e602921b6df --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/o2physics/AnalysisV0/strangeness_derived_v0_step4.cxx @@ -0,0 +1,336 @@ +// 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. +/// +/// \brief Step4 of the V0 strangeness tutorial on derived data (K0S, Lambda, AntiLambda) +/// \author Sara Pucillo +/// based on the O2AT strangeness derived-data tutorial from: +/// \author Romain Schotter +/// and on the original codes from: +/// \author Nepeivoda Roman (roman.nepeivoda@cern.ch) +/// \author Chiara De Martin (chiara.de.martin@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +// STEP 0 +// Starting point: loop over all V0s and fill invariant mass histograms +// STEP 1 +// Apply selections on topological variables of V0s +// STEP 2 +// Apply TPC PID selections on V0 daughter tracks +// STEP 3 +// Apply TOF PID selections on V0 daughter tracks (if info is available) +// STEP 4 +// Check the MC information of the V0s + +struct StrangenessDerivedV0Step4 { + // Histograms are defined with HistogramRegistry + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rK0Short{"kzeroShort", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rLambda{"lambda", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rGenParticles{"genParticles", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + // Configurable for histograms + Configurable nBins{"nBins", 100, "N bins in all histos"}; + + // Configurable for event selection + Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; + + // Configurable parameters for V0 selection + Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 0.5, "DCA V0 daughters"}; + Configurable v0setting_dcapostopv{"v0setting_dcapostopv", 0.06, "DCA positive to PV"}; + Configurable v0setting_dcanegtopv{"v0setting_dcanegtopv", 0.06, "DCA negative to PV"}; + Configurable v0setting_cospa{"v0setting_cospa", 0.995, "V0 CosPA"}; + Configurable v0setting_radius{"v0setting_radius", 0.9, "V0 radius"}; + Configurable v0setting_rapidity{"v0setting_rapidity", 0.5, "V0 rapidity window"}; + + // Configurable parameters for PID selection + Configurable NSigmaTPCPion{"NSigmaTPCPion", 4, "NSigmaTPCPion"}; + Configurable NSigmaTPCProton{"NSigmaTPCProton", 4, "NSigmaTPCProton"}; + + // Configurable parameters for TOF PID selection + Configurable NSigmaTOFPion{"NSigmaTOFPion", 3, "NSigmaTOFPion"}; + Configurable NSigmaTOFProton{"NSigmaTOFProton", 3, "NSigmaTOFProton"}; + + void init(InitContext const&) + { + // Axes + AxisSpec K0ShortMassAxis = {100, 0.45f, 0.55f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec LambdaMassAxis = {100, 1.08f, 1.15f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; + AxisSpec vertexZAxis = {nBins, -15., 15., "vrtx_{Z} [cm]"}; + AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec nSigmaAxis = {100, -10.0f, 10.0f, "N#sigma_{TPC}"}; + + // Histograms + // Event selection + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); + + // K0S/Lambda/AntiLambda reconstruction + rK0Short.add("hMassK0Short", "hMassK0Short", {HistType::kTH1F, {K0ShortMassAxis}}); + rK0Short.add("hMassK0ShortSelected", "hMassK0ShortSelected", {HistType::kTH1F, {K0ShortMassAxis}}); + rK0Short.add("hMassK0ShortSelectedWithTOF", "hMassK0ShortSelectedWithTOF", {HistType::kTH1F, {K0ShortMassAxis}}); + rK0Short.add("hMassK0ShortTrueRec", "hMassK0ShortTrueRec", {HistType::kTH1F, {K0ShortMassAxis}}); + rK0Short.add("hPtK0ShortTrueRec", "hPtK0ShortTrueRec", {HistType::kTH1F, {ptAxis}}); + rK0Short.add("hMassK0ShortTrueRecWithTOF", "hMassK0ShortTrueRecWithTOF", {HistType::kTH1F, {K0ShortMassAxis}}); + rK0Short.add("hPtK0ShortTrueRecWithTOF", "hPtK0ShortTrueRecWithTOF", {HistType::kTH1F, {ptAxis}}); + + rLambda.add("hMassLambda", "hMassLambda", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambda", "hMassAntiLambda", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassLambdaSelected", "hMassLambdaSelected", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambdaSelected", "hMassAntiLambdaSelected", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassLambdaSelectedWithTOF", "hMassLambdaSelectedWithTOF", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassAntiLambdaSelectedWithTOF", "hMassAntiLambdaSelectedWithTOF", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hMassLambdaTrueRec", "hMassLambdaTrueRec", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hPtLambdaTrueRec", "hPtLambdaTrueRec", {HistType::kTH1F, {ptAxis}}); + rLambda.add("hMassLambdaTrueRecWithTOF", "hMassLambdaTrueRecWithTOF", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hPtLambdaTrueRecWithTOF", "hPtLambdaTrueRecWithTOF", {HistType::kTH1F, {ptAxis}}); + rLambda.add("hMassAntiLambdaTrueRec", "hMassAntiLambdaTrueRec", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hPtAntiLambdaTrueRec", "hPtAntiLambdaTrueRec", {HistType::kTH1F, {ptAxis}}); + rLambda.add("hMassAntiLambdaTrueRecWithTOF", "hMassAntiLambdaTrueRecWithTOF", {HistType::kTH1F, {LambdaMassAxis}}); + rLambda.add("hPtAntiLambdaTrueRecWithTOF", "hPtAntiLambdaTrueRecWithTOF", {HistType::kTH1F, {ptAxis}}); + + // V0 topological variables (after selections) + rK0Short.add("hV0DCADaughters", "hV0DCADaughters", {HistType::kTH1F, {{55, 0.0f, 2.2f}}}); + rK0Short.add("hV0CosPA", "hV0CosPA", {HistType::kTH1F, {{100, 0.95f, 1.f}}}); + rK0Short.add("hV0Radius", "hV0Radius", {HistType::kTH1F, {{100, 0.0f, 50.0f}}}); + + // TPC PID of the K0S daughters, in the K0S peak region, before the PID selection + rK0Short.add("hNSigmaPosPionFromK0s", "hNSigmaPosPionFromK0s", {HistType::kTH2F, {ptAxis, nSigmaAxis}}); + rK0Short.add("hNSigmaNegPionFromK0s", "hNSigmaNegPionFromK0s", {HistType::kTH2F, {ptAxis, nSigmaAxis}}); + + // Generated level histograms + rEventSelection.add("hVertexZGen", "hVertexZGen", {HistType::kTH1F, {vertexZAxis}}); + rGenParticles.add("hPtK0ShortGen", "hPtK0ShortGen", {HistType::kTH1F, {ptAxis}}); + rGenParticles.add("hPtLambdaGen", "hPtLambdaGen", {HistType::kTH1F, {ptAxis}}); + rGenParticles.add("hPtAntiLambdaGen", "hPtAntiLambdaGen", {HistType::kTH1F, {ptAxis}}); + } + + // Defining filters for events (event selection) + // Processed events will be already fulfilling the event selection requirements + Filter eventFilter = (o2::aod::evsel::sel8 == true); + Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); + Filter posZFilterMC = (nabs(o2::aod::mccollision::posZ) < cutzvertex); + + // Filters on V0s + // Cannot filter on dynamic columns + Filter preFilterV0 = (aod::v0data::dcaV0daughters < v0setting_dcav0dau && + nabs(aod::v0data::dcapostopv) > v0setting_dcapostopv && + nabs(aod::v0data::dcanegtopv) > v0setting_dcanegtopv); + + // Defining the type of the daughter tracks + using dauTracks = soa::Join; + + void processRecMC(soa::Filtered>::iterator const& collision, + soa::Filtered> const& V0s, + dauTracks const&, + aod::V0MCCores const& /*v0mccores*/) + { + // Fill the event counter + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + + // V0s + for (const auto& v0 : V0s) { + const auto& posDaughterTrack = v0.posTrackExtra_as(); + const auto& negDaughterTrack = v0.negTrackExtra_as(); + + rK0Short.fill(HIST("hMassK0Short"), v0.mK0Short()); + rLambda.fill(HIST("hMassLambda"), v0.mLambda()); + rLambda.fill(HIST("hMassAntiLambda"), v0.mAntiLambda()); + + // Keep only standard V0s (type 1): type 0 = not passing the standard V0 selections, 2-3 = photon-like (TPC-only) + if (v0.v0Type() != 1) { + continue; + } + // Topological selections not applied in the Filter + // (in V0Cores the cosine of pointing angle is a regular column: it could also be moved into the Filter) + if (v0.v0cosPA() < v0setting_cospa) { + continue; + } + // Cut on dynamic columns + if (v0.v0radius() < v0setting_radius) { + continue; + } + // From here on, the same V0 is tested under the three mass hypotheses (K0S, Lambda, AntiLambda): + // the hypothesis-dependent selections cannot use 'continue', they are stored in booleans + + // Kinematic selection + bool isK0Short = std::abs(v0.yK0Short()) < v0setting_rapidity; + bool isLambda = std::abs(v0.yLambda()) < v0setting_rapidity; + bool isAntiLambda = std::abs(v0.yLambda()) < v0setting_rapidity; + + // TPC PID QA of the K0S daughters (in the K0S peak region, before the PID selection) + if (isK0Short && std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < 0.01) { + rK0Short.fill(HIST("hNSigmaPosPionFromK0s"), v0.positivept(), posDaughterTrack.tpcNSigmaPi()); + rK0Short.fill(HIST("hNSigmaNegPionFromK0s"), v0.negativept(), negDaughterTrack.tpcNSigmaPi()); + } + + // TPC PID selection + // K0S -> pi+ pi- + if (std::abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion || std::abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + isK0Short = false; + } + // Lambda -> p pi- + if (std::abs(posDaughterTrack.tpcNSigmaPr()) > NSigmaTPCProton || std::abs(negDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion) { + isLambda = false; + } + // AntiLambda -> pbar pi+ + if (std::abs(posDaughterTrack.tpcNSigmaPi()) > NSigmaTPCPion || std::abs(negDaughterTrack.tpcNSigmaPr()) > NSigmaTPCProton) { + isAntiLambda = false; + } + + // TOF PID check (applied only if the daughter has a TOF signal) + bool k0ShortPassTOFSelection = true; + bool lambdaPassTOFSelection = true; + bool antiLambdaPassTOFSelection = true; + if (v0.positiveHasTOF()) { + if (std::abs(v0.tofNSigmaK0PiPlus()) > NSigmaTOFPion) { + k0ShortPassTOFSelection &= false; + } + if (std::abs(v0.tofNSigmaLaPr()) > NSigmaTOFProton) { + lambdaPassTOFSelection &= false; + } + if (std::abs(v0.tofNSigmaALaPi()) > NSigmaTOFPion) { + antiLambdaPassTOFSelection &= false; + } + } + if (v0.negativeHasTOF()) { + if (std::abs(v0.tofNSigmaK0PiMinus()) > NSigmaTOFPion) { + k0ShortPassTOFSelection &= false; + } + if (std::abs(v0.tofNSigmaLaPi()) > NSigmaTOFPion) { + lambdaPassTOFSelection &= false; + } + if (std::abs(v0.tofNSigmaALaPr()) > NSigmaTOFProton) { + antiLambdaPassTOFSelection &= false; + } + } + // Equivalent short form: v0.tofK0ShortCompatibility(nSigma), v0.tofLambdaCompatibility(nSigma), ... + + // Fill histograms! (if possible) + if (isK0Short) { + rK0Short.fill(HIST("hMassK0ShortSelected"), v0.mK0Short()); + if (k0ShortPassTOFSelection) { + rK0Short.fill(HIST("hMassK0ShortSelectedWithTOF"), v0.mK0Short()); + } + + rK0Short.fill(HIST("hV0DCADaughters"), v0.dcaV0daughters()); + rK0Short.fill(HIST("hV0CosPA"), v0.v0cosPA()); + rK0Short.fill(HIST("hV0Radius"), v0.v0radius()); + } + if (isLambda) { + rLambda.fill(HIST("hMassLambdaSelected"), v0.mLambda()); + if (lambdaPassTOFSelection) { + rLambda.fill(HIST("hMassLambdaSelectedWithTOF"), v0.mLambda()); + } + } + if (isAntiLambda) { + rLambda.fill(HIST("hMassAntiLambdaSelected"), v0.mAntiLambda()); + if (antiLambdaPassTOFSelection) { + rLambda.fill(HIST("hMassAntiLambdaSelectedWithTOF"), v0.mAntiLambda()); + } + } + + // MC truth info + if (!v0.has_v0MCCore()) { + continue; + } + auto v0mccore = v0.v0MCCore_as(); + + // Efficiency is computed for primary particles only (e.g. Lambda from Xi decays are excluded) + if (!v0mccore.isPhysicalPrimary()) { + continue; + } + + // Checking that the V0 is a true K0S / Lambda / AntiLambda + if (v0mccore.pdgCode() == PDG_t::kK0Short && isK0Short) { + rK0Short.fill(HIST("hMassK0ShortTrueRec"), v0.mK0Short()); + rK0Short.fill(HIST("hPtK0ShortTrueRec"), v0.pt()); + if (k0ShortPassTOFSelection) { + rK0Short.fill(HIST("hMassK0ShortTrueRecWithTOF"), v0.mK0Short()); + rK0Short.fill(HIST("hPtK0ShortTrueRecWithTOF"), v0.pt()); + } + } + if (v0mccore.pdgCode() == PDG_t::kLambda0 && isLambda) { + rLambda.fill(HIST("hMassLambdaTrueRec"), v0.mLambda()); + rLambda.fill(HIST("hPtLambdaTrueRec"), v0.pt()); + if (lambdaPassTOFSelection) { + rLambda.fill(HIST("hMassLambdaTrueRecWithTOF"), v0.mLambda()); + rLambda.fill(HIST("hPtLambdaTrueRecWithTOF"), v0.pt()); + } + } + if (v0mccore.pdgCode() == PDG_t::kLambda0Bar && isAntiLambda) { + rLambda.fill(HIST("hMassAntiLambdaTrueRec"), v0.mAntiLambda()); + rLambda.fill(HIST("hPtAntiLambdaTrueRec"), v0.pt()); + if (antiLambdaPassTOFSelection) { + rLambda.fill(HIST("hMassAntiLambdaTrueRecWithTOF"), v0.mAntiLambda()); + rLambda.fill(HIST("hPtAntiLambdaTrueRecWithTOF"), v0.pt()); + } + } + } + } + + void processGenMC(soa::Filtered::iterator const& mcCollision, + const soa::SmallGroups>& collisions, + const soa::SmallGroups>& v0MC) + { + if (collisions.size() < 1) { // to process generated collisions that've been reconstructed at least once + return; + } + rEventSelection.fill(HIST("hVertexZGen"), mcCollision.posZ()); + + for (const auto& v0mc : v0MC) { + if (!v0mc.isPhysicalPrimary()) { + continue; + } + // rapidityMC(i): i = 0 -> K0S mass hypothesis, 1 -> Lambda, 2 -> AntiLambda + if (v0mc.pdgCode() == PDG_t::kK0Short && std::abs(v0mc.rapidityMC(0)) < v0setting_rapidity) { + rGenParticles.fill(HIST("hPtK0ShortGen"), v0mc.ptMC()); + } + if (v0mc.pdgCode() == PDG_t::kLambda0 && std::abs(v0mc.rapidityMC(1)) < v0setting_rapidity) { + rGenParticles.fill(HIST("hPtLambdaGen"), v0mc.ptMC()); + } + if (v0mc.pdgCode() == PDG_t::kLambda0Bar && std::abs(v0mc.rapidityMC(2)) < v0setting_rapidity) { + rGenParticles.fill(HIST("hPtAntiLambdaGen"), v0mc.ptMC()); + } + } + } + + PROCESS_SWITCH(StrangenessDerivedV0Step4, processRecMC, "Process Run 3 mc, reconstructed", true); + PROCESS_SWITCH(StrangenessDerivedV0Step4, processGenMC, "Process Run 3 mc, generated", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"strangeness-derived-v0-tutorial"})}; +} diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runSkeleton.sh b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runSkeleton.sh new file mode 100755 index 00000000000..1bc63dc4a72 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runSkeleton.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="skeleton" +LOGFILE="log-${STEP}.txt" + +# directory of this script +DIR_THIS="$(dirname "$(realpath "$0")")" + +# run from the folder of this script, so that the relative paths in input_data.txt work +cd "$DIR_THIS" || exit 1 + +# input: text file with the list of AO2D files to analyse (one path per line) +# default: real data, input_data.txt -> data/AO2D.root +# to run this step on the MC instead: INPUTFILE=input_MC.txt ./runSkeleton.sh +INPUTFILE="${INPUTFILE:-input_data.txt}" + +# Task to run. Default: the checkpoint of this step. +# To run YOUR code (the skeleton you are modifying) with the configuration of this step: +# TASK=o2-analysistutorial-lf-strangeness-derived-v0-skeleton ./runSkeleton.sh +TASK="${TASK:-o2-analysistutorial-lf-strangeness-derived-v0-skeleton}" + +OPTION="-b --configuration json://$DIR_THIS/jsonConfigs/$STEP.json" + +# If checkTables.C reports old table versions, prepend the suggested converters, e.g.: +# CONVERTERS='o2-analysis-lf-straevselsconverter6 ${OPTION} | ' ./runSkeleton.sh +CONVERTERS="${CONVERTERS:-}" +WORKFLOW="${TASK} ${OPTION}" + +eval "${CONVERTERS}${WORKFLOW} --aod-file @${INPUTFILE}" > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "$DIR_THIS/results/$STEP" + mv "AnalysisResults.root" "$DIR_THIS/results/$STEP/AnalysisResults.root" + mv "dpl-config.json" "$DIR_THIS/results/$STEP/dpl-config-$STEP.json" +else + echo "Error: Exit code $rc" + echo "Check the log file $LOGFILE" + exit $rc +fi diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep0.sh b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep0.sh new file mode 100755 index 00000000000..6b4acd5b7b1 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep0.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="step0" +LOGFILE="log-${STEP}.txt" + +# directory of this script +DIR_THIS="$(dirname "$(realpath "$0")")" + +# run from the folder of this script, so that the relative paths in input_data.txt work +cd "$DIR_THIS" || exit 1 + +# input: text file with the list of AO2D files to analyse (one path per line) +# default: real data, input_data.txt -> data/AO2D.root +# to run this step on the MC instead: INPUTFILE=input_MC.txt ./runStep0.sh +INPUTFILE="${INPUTFILE:-input_data.txt}" + +# Task to run. Default: the checkpoint of this step. +# To run YOUR code (the skeleton you are modifying) with the configuration of this step: +# TASK=o2-analysistutorial-lf-strangeness-derived-v0-skeleton ./runStep0.sh +TASK="${TASK:-o2-analysistutorial-lf-strangeness-derived-v0-step0}" + +OPTION="-b --configuration json://$DIR_THIS/jsonConfigs/$STEP.json" + +# If checkTables.C reports old table versions, prepend the suggested converters, e.g.: +# CONVERTERS='o2-analysis-lf-straevselsconverter6 ${OPTION} | ' ./runStep0.sh +CONVERTERS="${CONVERTERS:-}" +WORKFLOW="${TASK} ${OPTION}" + +eval "${CONVERTERS}${WORKFLOW} --aod-file @${INPUTFILE}" > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "$DIR_THIS/results/$STEP" + mv "AnalysisResults.root" "$DIR_THIS/results/$STEP/AnalysisResults.root" + mv "dpl-config.json" "$DIR_THIS/results/$STEP/dpl-config-$STEP.json" +else + echo "Error: Exit code $rc" + echo "Check the log file $LOGFILE" + exit $rc +fi diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep1.sh b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep1.sh new file mode 100755 index 00000000000..7f7bdd77e44 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep1.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="step1" +LOGFILE="log-${STEP}.txt" + +# directory of this script +DIR_THIS="$(dirname "$(realpath "$0")")" + +# run from the folder of this script, so that the relative paths in input_data.txt work +cd "$DIR_THIS" || exit 1 + +# input: text file with the list of AO2D files to analyse (one path per line) +# default: real data, input_data.txt -> data/AO2D.root +# to run this step on the MC instead: INPUTFILE=input_MC.txt ./runStep1.sh +INPUTFILE="${INPUTFILE:-input_data.txt}" + +# Task to run. Default: the checkpoint of this step. +# To run YOUR code (the skeleton you are modifying) with the configuration of this step: +# TASK=o2-analysistutorial-lf-strangeness-derived-v0-skeleton ./runStep1.sh +TASK="${TASK:-o2-analysistutorial-lf-strangeness-derived-v0-step1}" + +OPTION="-b --configuration json://$DIR_THIS/jsonConfigs/$STEP.json" + +# If checkTables.C reports old table versions, prepend the suggested converters, e.g.: +# CONVERTERS='o2-analysis-lf-straevselsconverter6 ${OPTION} | ' ./runStep1.sh +CONVERTERS="${CONVERTERS:-}" +WORKFLOW="${TASK} ${OPTION}" + +eval "${CONVERTERS}${WORKFLOW} --aod-file @${INPUTFILE}" > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "$DIR_THIS/results/$STEP" + mv "AnalysisResults.root" "$DIR_THIS/results/$STEP/AnalysisResults.root" + mv "dpl-config.json" "$DIR_THIS/results/$STEP/dpl-config-$STEP.json" +else + echo "Error: Exit code $rc" + echo "Check the log file $LOGFILE" + exit $rc +fi diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep2.sh b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep2.sh new file mode 100755 index 00000000000..320c60bdf30 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep2.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="step2" +LOGFILE="log-${STEP}.txt" + +# directory of this script +DIR_THIS="$(dirname "$(realpath "$0")")" + +# run from the folder of this script, so that the relative paths in input_data.txt work +cd "$DIR_THIS" || exit 1 + +# input: text file with the list of AO2D files to analyse (one path per line) +# default: real data, input_data.txt -> data/AO2D.root +# to run this step on the MC instead: INPUTFILE=input_MC.txt ./runStep2.sh +INPUTFILE="${INPUTFILE:-input_data.txt}" + +# Task to run. Default: the checkpoint of this step. +# To run YOUR code (the skeleton you are modifying) with the configuration of this step: +# TASK=o2-analysistutorial-lf-strangeness-derived-v0-skeleton ./runStep2.sh +TASK="${TASK:-o2-analysistutorial-lf-strangeness-derived-v0-step2}" + +OPTION="-b --configuration json://$DIR_THIS/jsonConfigs/$STEP.json" + +# If checkTables.C reports old table versions, prepend the suggested converters, e.g.: +# CONVERTERS='o2-analysis-lf-straevselsconverter6 ${OPTION} | ' ./runStep2.sh +CONVERTERS="${CONVERTERS:-}" +WORKFLOW="${TASK} ${OPTION}" + +eval "${CONVERTERS}${WORKFLOW} --aod-file @${INPUTFILE}" > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "$DIR_THIS/results/$STEP" + mv "AnalysisResults.root" "$DIR_THIS/results/$STEP/AnalysisResults.root" + mv "dpl-config.json" "$DIR_THIS/results/$STEP/dpl-config-$STEP.json" +else + echo "Error: Exit code $rc" + echo "Check the log file $LOGFILE" + exit $rc +fi diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep3.sh b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep3.sh new file mode 100755 index 00000000000..f2dab308652 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep3.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="step3" +LOGFILE="log-${STEP}.txt" + +# directory of this script +DIR_THIS="$(dirname "$(realpath "$0")")" + +# run from the folder of this script, so that the relative paths in input_data.txt work +cd "$DIR_THIS" || exit 1 + +# input: text file with the list of AO2D files to analyse (one path per line) +# default: real data, input_data.txt -> data/AO2D.root +# to run this step on the MC instead: INPUTFILE=input_MC.txt ./runStep3.sh +INPUTFILE="${INPUTFILE:-input_data.txt}" + +# Task to run. Default: the checkpoint of this step. +# To run YOUR code (the skeleton you are modifying) with the configuration of this step: +# TASK=o2-analysistutorial-lf-strangeness-derived-v0-skeleton ./runStep3.sh +TASK="${TASK:-o2-analysistutorial-lf-strangeness-derived-v0-step3}" + +OPTION="-b --configuration json://$DIR_THIS/jsonConfigs/$STEP.json" + +# If checkTables.C reports old table versions, prepend the suggested converters, e.g.: +# CONVERTERS='o2-analysis-lf-straevselsconverter6 ${OPTION} | ' ./runStep3.sh +CONVERTERS="${CONVERTERS:-}" +WORKFLOW="o2-analysis-lf-strangenesstofpid ${OPTION} | ${TASK} ${OPTION}" + +eval "${CONVERTERS}${WORKFLOW} --aod-file @${INPUTFILE}" > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "$DIR_THIS/results/$STEP" + mv "AnalysisResults.root" "$DIR_THIS/results/$STEP/AnalysisResults.root" + mv "dpl-config.json" "$DIR_THIS/results/$STEP/dpl-config-$STEP.json" +else + echo "Error: Exit code $rc" + echo "Check the log file $LOGFILE" + exit $rc +fi diff --git a/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep4.sh b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep4.sh new file mode 100755 index 00000000000..a619a856b91 --- /dev/null +++ b/Tutorials/PWGLF/Strangeness/StrangenessV0s_HandsOn/runStep4.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# log file where the terminal output will be saved +STEP="step4" +LOGFILE="log-${STEP}.txt" + +# directory of this script +DIR_THIS="$(dirname "$(realpath "$0")")" + +# run from the folder of this script, so that the relative paths in input_data.txt work +cd "$DIR_THIS" || exit 1 + +# input: text file with the list of AO2D files to analyse (one path per line) +# step 4 needs the MC truth: default input_MC.txt -> MC/AO2D.root +INPUTFILE="${INPUTFILE:-input_MC.txt}" + +# Task to run. Default: the checkpoint of this step. +# To run YOUR code (the skeleton you are modifying) with the configuration of this step: +# TASK=o2-analysistutorial-lf-strangeness-derived-v0-skeleton ./runStep4.sh +TASK="${TASK:-o2-analysistutorial-lf-strangeness-derived-v0-step4}" + +OPTION="-b --configuration json://$DIR_THIS/jsonConfigs/$STEP.json" + +# If checkTables.C reports old table versions, prepend the suggested converters, e.g.: +# CONVERTERS='o2-analysis-lf-straevselsconverter6 ${OPTION} | ' ./runStep4.sh +CONVERTERS="${CONVERTERS:-}" +WORKFLOW="o2-analysis-lf-strangenesstofpid ${OPTION} | ${TASK} ${OPTION}" + +eval "${CONVERTERS}${WORKFLOW} --aod-file @${INPUTFILE}" > "$LOGFILE" 2>&1 + +# report status +rc=$? +if [ $rc -eq 0 ]; then + echo "No problems!" + mkdir -p "$DIR_THIS/results/$STEP" + mv "AnalysisResults.root" "$DIR_THIS/results/$STEP/AnalysisResults.root" + mv "dpl-config.json" "$DIR_THIS/results/$STEP/dpl-config-$STEP.json" +else + echo "Error: Exit code $rc" + echo "Check the log file $LOGFILE" + exit $rc +fi