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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Tutorials/PWGLF/Strangeness/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@

add_subdirectory(Original)
add_subdirectory(Derived)

40 changes: 40 additions & 0 deletions Tutorials/PWGLF/Strangeness/Derived/AnalysisV0/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
118 changes: 118 additions & 0 deletions Tutorials/PWGLF/Strangeness/Derived/AnalysisV0/README.md
Original file line number Diff line number Diff line change
@@ -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
```

Go to the folder of the hands-on in your O2Physics source directory:

```bash
cd ~/alice/O2Physics/Tutorials/PWGLF/Strangeness/Derived/AnalysisV0
```

Download the two input files (strangeness derived data, ~<200> MB each):

```bash
mkdir -p data MC
# real data -> data/AO2D.root (used by skeleton and steps 0-3)
rsync -r -u --progress [email protected]:/eos/user/<u>/<user>/tutorialData/data/AO2D.root data
# Monte Carlo -> MC/AO2D.root (used by step 4, which needs the MC truth)
rsync -r -u --progress [email protected]:/eos/user/<u>/<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 this folder or absolute), which you have to create (the paths are also given in the slides):

```bash
echo "data/AO2D.root" > input_data.txt # used by runSkeleton.sh, runStep0-3.sh
echo "MC/AO2D.root" > input_MC.txt # used by 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 this folder:
`Tutorials/PWGLF/Strangeness/Derived/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<aod::V0MCCores>()`, `.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
```
139 changes: 139 additions & 0 deletions Tutorials/PWGLF/Strangeness/Derived/AnalysisV0/checkTables.C
Original file line number Diff line number Diff line change
@@ -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 <TCollection.h>
#include <TDirectory.h>
#include <TFile.h>
#include <TKey.h>
#include <TString.h>

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

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<TKey*>(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<RequiredTable> 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<TKey*>(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<TKey*>(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();
}
Original file line number Diff line number Diff line change
@@ -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": ""
}
Original file line number Diff line number Diff line change
@@ -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": ""
}
Original file line number Diff line number Diff line change
@@ -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": ""
}
Loading
Loading